From 1d0d4aae48120bb155ad83c4a2a1cfb18dca7764 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 15 Jul 2017 13:13:24 -0700 Subject: [PATCH 001/215] use openaps --nogit option --- bin/oref0-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index c6a87d9ef..563249cf4 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -499,7 +499,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then mkdir -p $directory if ( cd $directory && git status 2>/dev/null >/dev/null && openaps use -h >/dev/null ); then echo $directory already exists - elif openaps init $directory; then + elif openaps init $directory --nogit; then echo $directory initialized else die "Can't init $directory" From 6d808f2a954c114e7234686d8cd32134bbb0a16d Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 15 Jul 2017 15:06:30 -0700 Subject: [PATCH 002/215] --nogit for myopenaps-cgm-loop too --- bin/oref0-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 563249cf4..c6b95d265 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -657,7 +657,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then mkdir -p $directory-cgm-loop if ( cd $directory-cgm-loop && git status 2>/dev/null >/dev/null && openaps use -h >/dev/null ); then echo $directory-cgm-loop already exists - elif openaps init $directory-cgm-loop; then + elif openaps init $directory-cgm-loop --nogit; then echo $directory-cgm-loop initialized else die "Can't init $directory-cgm-loop" From f5317c9e6133f23393ab0ed657b62b408a8122c7 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 15 Jul 2017 15:13:48 -0700 Subject: [PATCH 003/215] remove git-specific stuff --- bin/oref0-setup.sh | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index c6b95d265..6dc792c00 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -138,16 +138,6 @@ if ! [[ ${CGM,,} =~ "g4-upload" || ${CGM,,} =~ "g5" || ${CGM,,} =~ "mdt" || ${CG echo DIR="" # to force a Usage prompt fi -if ! ( git config -l | grep -q user.email ) ; then - read -p "What email address would you like to use for git commits? " -r - EMAIL=$REPLY - git config --global user.email $EMAIL -fi -if ! ( git config -l | grep -q user.name ); then - read -p "What full name would you like to use for git commits? " -r - NAME=$REPLY - git config --global user.name $NAME -fi if [[ -z "$DIR" || -z "$serial" ]]; then echo "Usage: oref0-setup.sh <--dir=directory> <--serial=pump_serial_#> [--tty=/dev/ttySOMETHING] [--max_iob=0] [--ns-host=https://mynightscout.herokuapp.com] [--api-secret=[myplaintextapisecret|token=subjectname-plaintexthashsecret] [--cgm=(G4-upload|G4-local-only|shareble|G5|MDT|xdrip)] [--bleserial=SM123456] [--blemac=FE:DC:BA:98:76:54] [--btmac=AB:CD:EF:01:23:45] [--enable='autosens meal dexusb'] [--radio_locale=(WW|US)] [--ww_ti_usb_reset=(yes|no)]" echo @@ -497,7 +487,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then echo -n "Checking $directory: " mkdir -p $directory - if ( cd $directory && git status 2>/dev/null >/dev/null && openaps use -h >/dev/null ); then + if ( cd $directory && ls openaps.ini 2>/dev/null >/dev/null && openaps use -h >/dev/null ); then echo $directory already exists elif openaps init $directory --nogit; then echo $directory initialized @@ -533,9 +523,9 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then echo Checking oref0 installation cd $HOME/src/oref0 if git branch | grep "* master"; then - npm list -g oref0 | egrep oref0@0.5.0 || (echo Installing latest oref0 package && sudo npm install -g oref0) + npm list -g oref0 | egrep oref0@0.5.[0-1] || (echo Installing latest oref0 package && sudo npm install -g oref0) else - npm list -g oref0 | egrep oref0@0.5.[1-9] || (echo Installing latest oref0 from $HOME/src/oref0/ && cd $HOME/src/oref0/ && npm run global-install) + npm list -g oref0 | egrep oref0@0.5.[2-9] || (echo Installing latest oref0 from $HOME/src/oref0/ && cd $HOME/src/oref0/ && npm run global-install) fi echo Checking mmeowlink installation @@ -572,7 +562,6 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then fi cat preferences.json - git add preferences.json # enable log rotation sudo cp $HOME/src/oref0/logrotate.openaps /etc/logrotate.d/openaps || die "Could not cp /etc/logrotate.d/openaps" @@ -655,7 +644,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ ${CGM,,} =~ "shareble" || ${CGM,,} =~ "g4-upload" ]]; then mkdir -p $directory-cgm-loop - if ( cd $directory-cgm-loop && git status 2>/dev/null >/dev/null && openaps use -h >/dev/null ); then + if ( cd $directory-cgm-loop && ls openaps.ini 2>/dev/null >/dev/null && openaps use -h >/dev/null ); then echo $directory-cgm-loop already exists elif openaps init $directory-cgm-loop --nogit; then echo $directory-cgm-loop initialized @@ -703,8 +692,6 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then cd $directory || die "Can't cd $directory" fi - grep -q pump.ini .gitignore 2>/dev/null || echo pump.ini >> .gitignore - git add .gitignore if [[ "$ttyport" =~ "spi" ]]; then echo Checking kernel for spi_serial installation @@ -948,15 +935,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then (crontab -l; crontab -l | grep -q "killall -g --older-than 30m oref0" || echo '* * * * * ( killall -g --older-than 30m openaps; killall -g --older-than 30m oref0-pump-loop; killall -g --older-than 30m openaps-report )') | crontab - # kill pump-loop after 5 minutes of not writing to pump-loop.log (crontab -l; crontab -l | grep -q "killall -g --older-than 5m oref0" || echo '* * * * * find /var/log/openaps/pump-loop.log -mmin +5 | grep pump && ( killall -g --older-than 5m openaps; killall -g --older-than 5m oref0-pump-loop; killall -g --older-than 5m openaps-report )') | crontab - - # repair or reset git repository if it's corrupted or disk is full - (crontab -l; crontab -l | grep -q "cd $directory && oref0-reset-git" || echo "* * * * * cd $directory && oref0-reset-git") | crontab - - # truncate git history to 1000 commits if it has grown past 1500 - (crontab -l; crontab -l | grep -q "oref0-truncate-git-history" || echo "* * * * * cd $directory && ps aux | grep -v grep | grep -q oref0-truncate-git-history || oref0-truncate-git-history") | crontab - if [[ ${CGM,,} =~ "shareble" || ${CGM,,} =~ "g4-upload" ]]; then - # repair or reset cgm-loop git repository if it's corrupted or disk is full - (crontab -l; crontab -l | grep -q "cd $directory-cgm-loop && oref0-reset-git" || echo "* * * * * cd $directory-cgm-loop && oref0-reset-git") | crontab - - # truncate cgm-loop git history to 1000 commits if it has grown past 1500 - (crontab -l; crontab -l | grep -q "cd $directory-cgm-loop && oref0-truncate-git-history" || echo "* * * * * cd $directory-cgm-loop && oref0-truncate-git-history") | crontab - (crontab -l; crontab -l | grep -q "cd $directory-cgm-loop && ps aux | grep -v grep | grep -q 'openaps monitor-cgm'" || echo "* * * * * cd $directory-cgm-loop && ps aux | grep -v grep | grep -q 'openaps monitor-cgm' || ( date; openaps monitor-cgm) | tee -a /var/log/openaps/cgm-loop.log; cp -up monitor/glucose-raw-merge.json $directory/cgm/glucose.json ; cp -up $directory/cgm/glucose.json $directory/monitor/glucose.json") | crontab - elif [[ ${CGM,,} =~ "xdrip" ]]; then (crontab -l; crontab -l | grep -q "cd $directory && ps aux | grep -v grep | grep -q 'openaps monitor-xdrip'" || echo "* * * * * cd $directory && ps aux | grep -v grep | grep -q 'openaps monitor-xdrip' || ( date; cp -rf xdrip/glucose.json xdrip/last-glucose.json; openaps monitor-xdrip) | tee -a /var/log/openaps/xdrip-loop.log; cmp --silent xdrip/glucose.json xdrip/last-glucose.json || cp -up $directory/xdrip/glucose.json $directory/monitor/glucose.json") | crontab - From 4da025d6e8b1279b2c8c3d000efeeaef771cba5b Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 21 Jul 2017 21:52:49 -0700 Subject: [PATCH 004/215] enable SMB/UAM (if enabled in preferences) for a full 6 hours after any carb entry --- lib/determine-basal/determine-basal.js | 10 +++++++--- lib/profile/index.js | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index ebc959bdf..03a99a347 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -261,15 +261,19 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // disable SMB when a high temptarget is set if (profile.temptargetSet && target_bg > 100) { enableSMB=false; - // enable SMB (if enabled in preferences) for DIA hours after bolus + // enable SMB/UAM (if enabled in preferences) for DIA hours after bolus } else if (profile.enableSMB_with_bolus && bolusiob > 0.1) { enableSMB=true; - // enable SMB (if enabled in preferences) while we have COB + // enable SMB/UAM (if enabled in preferences) while we have COB } else if (profile.enableSMB_with_COB && meal_data.mealCOB) { enableSMB=true; - // enable SMB (if enabled in preferences) if a low temptarget is set + // enable SMB/UAM (if enabled in preferences) if a low temptarget is set } else if (profile.enableSMB_with_temptarget && (profile.temptargetSet && target_bg < 100)) { enableSMB=true; + // enable SMB/UAM (if enabled in preferences) for a full 6 hours after any carb entry + // (6 hours is defined in carbWindow in lib/meal/total.js) + } else if (profile.enableSMB_after_carbs && meal_data.carbs) { + enableSMB=true; } // enable UAM (if enabled in preferences) for DIA hours after bolus, or if SMB is enabled var enableUAM=(profile.enableUAM && (bolusiob > 0.1 || enableSMB)); diff --git a/lib/profile/index.js b/lib/profile/index.js index a1d607bab..73789eaec 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -33,6 +33,7 @@ function defaults ( ) { , enableSMB_with_bolus: false // enable supermicrobolus for DIA hours after a manual bolus , enableSMB_with_COB: false // enable supermicrobolus while COB is positive , enableSMB_with_temptarget: false // enable supermicrobolus for eating soon temp targets + , enableSMB_after_carbs: false // enable supermicrobolus for 6h after carbs, even with 0 COB }; return profile; } From 418cc9734e439931626bed34495b89c0e5352952 Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 21 Jul 2017 23:15:58 -0700 Subject: [PATCH 005/215] refresh pumphistory when pump is suspended and we can't enact --- bin/oref0-pump-loop.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 34d09a333..c4aea4995 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -196,6 +196,7 @@ function smb_verify_status { && if grep -q '"suspended": true' monitor/status.json; then echo -n "Pump suspended; " unsuspend_if_no_temp + gather fi } From d338151ec17a477e641359f2399169a017755642 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 29 Jul 2017 14:01:48 -0700 Subject: [PATCH 006/215] check whether decocare-0.0.31 has been installed --- bin/oref0-setup.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 363f41c5e..86181d5e4 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -522,9 +522,11 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then mkdir -p xdrip || die "Can't mkdir xdrip" fi - # install decocare with setuptools since 0.0.31 (with the 6.4U/h fix) isn't published properly to pypi - - sudo easy_install -U decocare || die "Can't easy_install decocare" + # check whether decocare-0.0.31 has been installed + if ! ls /usr/local/lib/python2.7/dist-packages/decocare-0.0.31-py2.7.egg/ 2>/dev/null >/dev/null; then + # install decocare with setuptools since 0.0.31 (with the 6.4U/h fix) isn't published properly to pypi + sudo easy_install -U decocare || die "Can't easy_install decocare" + fi mkdir -p $HOME/src/ if [ -d "$HOME/src/oref0/" ]; then From ee7271efd6e6ea706d24b84c287e0a7a60a12408 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 29 Jul 2017 14:22:37 -0700 Subject: [PATCH 007/215] automatically install openaps 0.2.1 with --nogit support --- bin/oref0-setup.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 5d01105d0..901e881b3 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -485,6 +485,12 @@ echocolor-n "Continue? y/[N] " read -r if [[ $REPLY =~ ^[Yy]$ ]]; then + # TODO: delete this after openaps 0.2.1 release + echo Checking openaps 0.2.1 installation with --nogit support + if ! openaps --version 2>&1 | egrep "0.[2-9].[1-9]"; then + echo Installing latest openaps w/ nogit && sudo pip install git+https://github.com/openaps/openaps.git@nogit || die "Couldn't install openaps w/ nogit" + fi + echo -n "Checking $directory: " mkdir -p $directory if ( cd $directory && ls openaps.ini 2>/dev/null >/dev/null && openaps use -h >/dev/null ); then From e744e4e621d336a07f96d7bb72f0f00272d9aec2 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 29 Jul 2017 21:15:44 -0700 Subject: [PATCH 008/215] check radio twice, and mmtune if both checks fail --- bin/oref0-pump-loop.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 916b912e7..e96992a24 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -347,6 +347,10 @@ function maybe_mmtune { && mmtune } +function any_pump_comms { + mmeowlink-any-pump-comms.py --port $port --wait-for $1 +} + # listen for $1 seconds of silence (no other rigs talking to pump) before continuing function wait_for_silence { if [ -z $1 ]; then @@ -354,11 +358,13 @@ function wait_for_silence { else waitfor=$1 fi - ((mmeowlink-any-pump-comms.py --port $port --wait-for 1 | grep -q comms) 2>&1 | tail -1 && echo -n "Radio ok. " || mmtune) \ - && echo -n "Listening: " + # check radio twice, and mmtune if both checks fail + ( ( any_pump_comms 1 | grep -q comms ) || ( any_pump_comms 1 | grep -q comms) ) 2>&1 | tail -1 \ + && echo -n "Radio ok. " || mmtune + echo -n "Listening: " for i in $(seq 1 800); do echo -n . - mmeowlink-any-pump-comms.py --port $port --wait-for $waitfor 2>/dev/null | egrep -v subg | egrep No \ + any_pump_comms $waitfor 2>/dev/null | egrep -v subg | egrep No \ && break done } From 7590fbfb0ddfc2dbe539b27a66c39c19b010d865 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 29 Jul 2017 21:28:35 -0700 Subject: [PATCH 009/215] use any_pump_comms function --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index e96992a24..a4dd91811 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -324,7 +324,7 @@ function mmtune { echo -n "Listening for 30s silence before mmtuning: " for i in $(seq 1 800); do echo -n . - mmeowlink-any-pump-comms.py --port $port --wait-for 30 2>/dev/null | egrep -v subg | egrep No \ + any_pump_comms 30 2>/dev/null | egrep -v subg | egrep No \ && break done echo {} > monitor/mmtune.json From 2504e5546c9288f3b727467f183ef23137e236c5 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 29 Jul 2017 21:29:34 -0700 Subject: [PATCH 010/215] debugging --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index a4dd91811..dbc8a50f3 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -360,7 +360,7 @@ function wait_for_silence { fi # check radio twice, and mmtune if both checks fail ( ( any_pump_comms 1 | grep -q comms ) || ( any_pump_comms 1 | grep -q comms) ) 2>&1 | tail -1 \ - && echo -n "Radio ok. " || mmtune + && echo -n "Radio ok. " || (any_pump_comms 1; mmtune) echo -n "Listening: " for i in $(seq 1 800); do echo -n . From 77ea0df21daf2c3707a568c254f119615ee3f9a2 Mon Sep 17 00:00:00 2001 From: Dana Lewis Date: Tue, 8 Aug 2017 16:39:09 -0700 Subject: [PATCH 011/215] Calling out the number one beginner error Number one error for beginners that blocks looping is when people don't have the pump set to absolute u/hr (in % basal type instead), which prevents the rig from being able to set temp basals. --- bin/oref0-pump-loop.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 34d09a333..c91cd6c6f 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -32,6 +32,10 @@ smb_main() { prep if ! ( \ prep + # checking to see if the log reports out that it's on % basal type, which blocks remote temps being set + if grep -q '"Temp":"percent"' monitor/temp_basal.json; then + echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." + fi echo && echo Starting supermicrobolus pump-loop at $(date) with $upto30s second wait_for_silence: \ && wait_for_bg \ && wait_for_silence $upto30s \ From 68ee1ce61ab1bb181f37beb70ea5f2156413b69a Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Fri, 11 Aug 2017 11:43:16 -0700 Subject: [PATCH 012/215] oref0-pump-loop reliability and debugging improvements (#575) * echo status * try preflight twice * check radio 10x, and mmtune if all checks fail * echo Preflight when starting it * mmtune 30% of the time * it's ok if refresh_profile or refresh_pumphistory_24h fail * Revert "check radio 10x, and mmtune if all checks fail" This reverts commit 6ea86371d33325275d12ab6186a1f579e45633c4. * remove extra any_pump_comms debugging * removing duplicate 30s wait_for_silence before mmtune * show just last line of any_pump_comms 1 output when Radio check fails * check radio thrice * echo "Done waiting for rigs with better signal." * case-insensitive grep to match 'Comms with pump detected' too * print when preflight fails * retry radio check one more time * exponential backoff on Radio check * echo -n . when retrying Radio check * print any_pump_comms output when it doesn't succeed * ignore mmeowlink-any-pump-comms.py exit code and just check output * reduce debugging --- bin/oref0-pump-loop.sh | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index dbc8a50f3..0f6552887 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -35,7 +35,7 @@ smb_main() { echo && echo Starting supermicrobolus pump-loop at $(date) with $upto30s second wait_for_silence: \ && wait_for_bg \ && wait_for_silence $upto30s \ - && preflight \ + && ( preflight || preflight ) \ && if_mdt_get_bg \ && refresh_old_pumphistory_24h \ && refresh_old_pumphistory \ @@ -58,12 +58,12 @@ smb_main() { )) fi ) \ - && refresh_profile \ - && refresh_pumphistory_24h \ + && ( refresh_profile; refresh_pumphistory_24h; true ) \ && echo Completed supermicrobolus pump-loop at $(date): \ && touch monitor/pump_loop_completed -r monitor/pump_loop_enacted \ && echo \ ); then + echo -n "SMB pump-loop failed. " maybe_mmtune echo Unsuccessful supermicrobolus pump-loop at $(date) fi @@ -308,10 +308,12 @@ function mdt_get_bg { } # make sure we can talk to the pump and get a valid model number function preflight { + echo -n "Preflight " # only 515, 522, 523, 715, 722, 723, 554, and 754 pump models have been tested with SMB ( openaps report invoke settings/model.json || openaps report invoke settings/model.json ) 2>&1 >/dev/null | tail -1 \ && egrep -q "[57](15|22|23|54)" settings/model.json \ - && echo -n "Preflight OK. " + && echo -n "OK. " \ + || ( echo -n "fail. "; false ) } # reset radio, init world wide pump (if applicable), mmtune, and wait_for_silence 60 if no signal @@ -336,14 +338,14 @@ function mmtune { if [[ $rssi_wait > 1 ]]; then echo "waiting for $rssi_wait second silence before continuing" wait_for_silence $rssi_wait + echo "Done waiting for rigs with better signal." fi } function maybe_mmtune { - # mmtune ~ 25% of the time - [[ $(( ( RANDOM % 100 ) )) > 75 ]] \ - && echo "Waiting for 30s silence before mmtuning" \ - && wait_for_silence 30 \ + # mmtune 30% of the time + [[ $(( ( RANDOM % 100 ) )) > 70 ]] \ + && echo "mmtuning" \ && mmtune } @@ -358,9 +360,14 @@ function wait_for_silence { else waitfor=$1 fi - # check radio twice, and mmtune if both checks fail - ( ( any_pump_comms 1 | grep -q comms ) || ( any_pump_comms 1 | grep -q comms) ) 2>&1 | tail -1 \ - && echo -n "Radio ok. " || (any_pump_comms 1; mmtune) + # check radio multiple times, and mmtune if all checks fail + ( ( out=$(any_pump_comms 1) ; echo $out | grep -qi comms || (echo $out; false) ) || \ + ( echo -n .; sleep 1; out=$(any_pump_comms 1) ; echo $out | grep -qi comms || (echo $out; false) ) || \ + ( echo -n .; sleep 2; out=$(any_pump_comms 1) ; echo $out | grep -qi comms || (echo $out; false) ) || \ + ( echo -n .; sleep 4; out=$(any_pump_comms 1) ; echo $out | grep -qi comms || (echo $out; false) ) || \ + ( echo -n .; sleep 8; out=$(any_pump_comms 1) ; echo $out | grep -qi comms || (echo $out; false) ) + ) 2>&1 | tail -2 \ + && echo -n "Radio ok. " || (echo -n "Radio check failed. "; any_pump_comms 1 2>&1 | tail -1; mmtune) echo -n "Listening: " for i in $(seq 1 800); do echo -n . From e9478ecfa8c10c1b4253b35a422624e09094399d Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 11 Aug 2017 13:22:12 -0700 Subject: [PATCH 013/215] if currentDeviation is null or maxDeviation is 0, set mealCOB to 0 for zombie-carb safety --- lib/meal/total.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/meal/total.js b/lib/meal/total.js index cfa2ed875..739b3249c 100644 --- a/lib/meal/total.js +++ b/lib/meal/total.js @@ -67,6 +67,17 @@ function diaCarbs(opts, time) { // set a hard upper limit on COB to mitigate impact of erroneous or malicious carb entry mealCOB = Math.min( profile.maxCOB, mealCOB ); + // if currentDeviation is null or maxDeviation is 0, set mealCOB to 0 for zombie-carb safety + if (typeof(c.currentDeviation) === 'undefined' || c.currentDeviation === null) { + console.error("Warning: setting mealCOB to 0 because currentDeviation is null/undefined"); + mealCOB = 0; + } + if (typeof(c.maxDeviation) === 'undefined' || c.maxDeviation === null) { + console.error("Warning: setting mealCOB to 0 because maxDeviation is 0 or undefined"); + mealCOB = 0; + } + + return { carbs: Math.round( carbs * 1000 ) / 1000 , boluses: Math.round( boluses * 1000 ) / 1000 From 5c54df49c4add0ac9b4e333e884111cf5e6bfd72 Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 11 Aug 2017 20:56:38 -0700 Subject: [PATCH 014/215] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0101ef8c6..dd8f15585 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oref0", - "version": "0.5.2", + "version": "0.6.0-dev", "description": "openaps oref0 reference implementation of the reference design", "scripts": { "test": "make test", From 58a987e6f98cfc38e4b66b1037e0a299f16110bd Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 11 Aug 2017 23:48:56 -0700 Subject: [PATCH 015/215] speed up COB calculation --- lib/determine-basal/cob-autosens.js | 2 +- lib/iob/index.js | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/determine-basal/cob-autosens.js b/lib/determine-basal/cob-autosens.js index 9bac13443..746fe8543 100644 --- a/lib/determine-basal/cob-autosens.js +++ b/lib/determine-basal/cob-autosens.js @@ -148,7 +148,7 @@ function detectSensitivityandCarbAbsorption(inputs) { iob_inputs.clock=bgTime; iob_inputs.profile.current_basal = basal.basalLookup(basalprofile, bgTime); //console.log(JSON.stringify(iob_inputs.profile)); - var iob = get_iob(iob_inputs)[0]; + var iob = get_iob(iob_inputs, true)[0]; //console.log(JSON.stringify(iob)); var bgi = Math.round(( -iob.activity * sens * 5 )*100)/100; diff --git a/lib/iob/index.js b/lib/iob/index.js index 3d48ac5ca..ec1a89bdd 100644 --- a/lib/iob/index.js +++ b/lib/iob/index.js @@ -4,7 +4,7 @@ var find_insulin = require('./history'); var calculate = require('./calculate'); var sum = require('./total'); -function generate (inputs) { +function generate (inputs, currentIOBOnly) { var treatments = find_insulin(inputs); @@ -30,8 +30,15 @@ function generate (inputs) { } //if (treatment.insulin && treatment.started_at) { console.error(treatment.insulin,treatment.started_at,lastBolusTime); } }); - // predict IOB out to DIA plus 30m to account for any running temp basals - for (i=0; i<((inputs.profile.dia*60)+30); i+=5){ + var iStop; + if (currentIOBOnly) { + // for COB calculation, we only need the zeroth element of iobArray + iStop=1 + } else { + // predict IOB out to DIA plus 30m to account for any running temp basals + iStop=(inputs.profile.dia*60)+30; + } + for (i=0; i Date: Sat, 12 Aug 2017 00:09:47 -0700 Subject: [PATCH 016/215] remove ' that is confusing vim; indentation --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 35385e00d..f11ed53d2 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -32,7 +32,7 @@ smb_main() { prep if ! ( \ prep - # checking to see if the log reports out that it's on % basal type, which blocks remote temps being set + # checking to see if the log reports out that it is on % basal type, which blocks remote temps being set if grep -q '"Temp":"percent"' monitor/temp_basal.json; then echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." fi From c8fbd37224bed91d1a8852efa2d5b538080c92fb Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 12 Aug 2017 08:37:47 -0700 Subject: [PATCH 017/215] chmod +x bin/oref0_nightscout_check.py --- bin/oref0_nightscout_check.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/oref0_nightscout_check.py diff --git a/bin/oref0_nightscout_check.py b/bin/oref0_nightscout_check.py old mode 100644 new mode 100755 From 71809c589efa107eeef6ddffdda04d395f5b51d9 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 12 Aug 2017 08:45:41 -0700 Subject: [PATCH 018/215] refresh meal.json after merge_pumphistory --- bin/oref0-pump-loop.sh | 5 ++++- lib/determine-basal/cob-autosens.js | 2 +- lib/oref0-setup/alias.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 916b912e7..ba103da77 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -372,7 +372,10 @@ function gather { && ( openaps monitor-pump || openaps monitor-pump ) 2>&1 >/dev/null | tail -1 \ && echo -n ed \ && merge_pumphistory \ - && echo " pumphistory" || (echo; exit 1) 2>/dev/null + && echo " pumphistory" \ + && openaps report invoke monitor/meal.json 2>&1 >/dev/null | tail -1 \ + && echo " and meal.json" \ + || (echo; exit 1) 2>/dev/null } function merge_pumphistory { diff --git a/lib/determine-basal/cob-autosens.js b/lib/determine-basal/cob-autosens.js index 9bac13443..9dc9c8783 100644 --- a/lib/determine-basal/cob-autosens.js +++ b/lib/determine-basal/cob-autosens.js @@ -106,7 +106,7 @@ function detectSensitivityandCarbAbsorption(inputs) { //console.error(gapDelta, lastbg, elapsed_minutes); nextbg = lastbg + (5/elapsed_minutes * gapDelta); bucketed_data[j].glucose = Math.round(nextbg); - console.error("Interpolated", bucketed_data[j]); + //console.error("Interpolated", bucketed_data[j]); elapsed_minutes = elapsed_minutes - 5; lastbg = nextbg; diff --git a/lib/oref0-setup/alias.json b/lib/oref0-setup/alias.json index c879157a3..7982cd9e3 100644 --- a/lib/oref0-setup/alias.json +++ b/lib/oref0-setup/alias.json @@ -43,7 +43,7 @@ }, { "monitor-pump": { - "command": "report invoke monitor/clock.json monitor/temp_basal.json monitor/pumphistory.json monitor/pumphistory-zoned.json monitor/clock-zoned.json monitor/iob.json monitor/meal.json monitor/reservoir.json monitor/battery.json monitor/status.json" + "command": "report invoke monitor/clock.json monitor/temp_basal.json monitor/pumphistory.json monitor/pumphistory-zoned.json monitor/clock-zoned.json monitor/iob.json monitor/reservoir.json monitor/battery.json monitor/status.json" }, "type": "alias", "name": "monitor-pump" From 7bb203371108b15ecb5702d4f6e0a8c978a4bf81 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 12 Aug 2017 08:51:55 -0700 Subject: [PATCH 019/215] newline --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index ba103da77..422e0a83e 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -372,7 +372,7 @@ function gather { && ( openaps monitor-pump || openaps monitor-pump ) 2>&1 >/dev/null | tail -1 \ && echo -n ed \ && merge_pumphistory \ - && echo " pumphistory" \ + && echo -n " pumphistory" \ && openaps report invoke monitor/meal.json 2>&1 >/dev/null | tail -1 \ && echo " and meal.json" \ || (echo; exit 1) 2>/dev/null From 3c989c909569babf735945d972f745ccaffbdc27 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Aug 2017 02:03:19 -0700 Subject: [PATCH 020/215] don't SMB unless bg > threshold (#602) * if currentDeviation is null or maxDeviation is 0, set mealCOB to 0 for zombie-carb safety (#589) * don't SMB unless bg > threshold --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 03a99a347..215e6f195 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -796,7 +796,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //console.error(profile.temptargetSet, target_bg, rT.COB); // only allow microboluses with COB or low temp targets, or within DIA hours of a bolus // only microbolus if 0.1U SMB represents 20m or less of basal (0.3U/hr or higher) - if (microBolusAllowed && enableSMB && profile.current_basal >= 0.3) { + if (microBolusAllowed && enableSMB && profile.current_basal >= 0.3 && bg > threshold) { // never bolus more than 30m worth of basal maxBolus = round(profile.current_basal/2,1); // bolus 1/3 the insulinReq, up to maxBolus From 9683781294dcf30c37185b6ec2cf8f1ad6430fc5 Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Sun, 13 Aug 2017 20:36:29 +0300 Subject: [PATCH 021/215] Exponential curves (#568) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix require() statements to work with Node 8 * Change to determine_basal that exposes behavior changes * Oops can’t do that simplification * Fiasp curve * removed debug logging * peak configuration, support old bilinear model * Changes to code structure, more tests * Revert a require() change that was included accidentally * Another change revert, needs testing outside the scope of Fiasp * Removing accidental formatting changes * Force IOB to 0 if over 5 hours have passed. Added tests, support for Novo peak scaling. AUC normalized for activity. * Renamed the curves for consistency * Small speedup to IOB calculation, use consistent date value if missing, added default curve to profile to ensure the correct curve is used * New generic curves * Corrected error logging * simply calculate biobContrib using 2t instead of t * Fixed bolus snooze test data to match the new calculation method * unit test for COB calculation - note the math is unverified. New logic for ISF fetching. Bug fix COB calculation if only one event is presented. Sort glucose data to match later logic assumptions. * Testing if removing package-lock.json fixes the build * Testing relative require paths in case that makes the server happy, fixed formatting * Fix test name, add travis build with Node 8 * Revert "Merge branch 'cob-test' into 0.6.0-dev" This reverts commit 72a60d90d8805f0904630fc6a5863d078ab6cbe6, reversing changes made to 547376a45684771161de4e9b637d1b835d089ed9. Conflicts: lib/iob/total.js * chmod +x bin/oref0_nightscout_check.py --- lib/iob/calculate.js | 134 ++++- lib/iob/total.js | 38 +- lib/profile/index.js | 3 + tests/iob.test.js | 1303 ++++++++++++++++++++++++++++++------------ 4 files changed, 1100 insertions(+), 378 deletions(-) diff --git a/lib/iob/calculate.js b/lib/iob/calculate.js index 3f8ff5059..1aed98cbd 100644 --- a/lib/iob/calculate.js +++ b/lib/iob/calculate.js @@ -1,9 +1,32 @@ +var _ = require('lodash'); +var timeRef = new Date(); -function iobCalc(treatment, time, dia) { +// from: https://stackoverflow.com/a/14873282 +function erf(x) { + // save the sign of x + var sign = (x >= 0) ? 1 : -1; + x = Math.abs(x); + + // constants + var a1 = 0.254829592; + var a2 = -0.284496736; + var a3 = 1.421413741; + var a4 = -1.453152027; + var a5 = 1.061405429; + var p = 0.3275911; + + // A&S formula 7.1.26 + var t = 1.0 / (1.0 + p * x); + var y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x); + return sign * y; // erf(-x) = -erf(x); +} + +// This is the old bilinear IOB curve model + +function iobCalcBiLinear(treatment, time, dia) { var diaratio = 3.0 / dia; - var peak = 75 ; - var end = 180 ; - //var sens = profile_data.sens; + var peak = 75; + var end = 180; if (typeof time === 'undefined') { time = new Date(); } @@ -12,19 +35,17 @@ function iobCalc(treatment, time, dia) { if (treatment.insulin) { var bolusTime = new Date(treatment.date); - var minAgo = diaratio * (time-bolusTime) / 1000 / 60; + var minAgo = diaratio * (time - bolusTime) / 1000 / 60; var iobContrib = 0; var activityContrib = 0; if (minAgo < peak) { - var x = (minAgo/5 + 1); + var x = (minAgo / 5 + 1); iobContrib = treatment.insulin * (1 - 0.001852 * x * x + 0.001852 * x); - //activityContrib=sens*treatment.insulin*(2/dia/60/peak)*minAgo; activityContrib = treatment.insulin * (2 / dia / 60 / peak) * minAgo; } else if (minAgo < end) { - var y = (minAgo-peak)/5; + var y = (minAgo - peak) / 5; iobContrib = treatment.insulin * (0.001323 * y * y - .054233 * y + .55556); - //activityContrib=sens*treatment.insulin*(2/dia/60-(minAgo-peak)*2/dia/60/(60*dia-peak)); activityContrib = treatment.insulin * (2 / dia / 60 - (minAgo - peak) * 2 / dia / 60 / (60 * 3 - peak)); } @@ -37,4 +58,99 @@ function iobCalc(treatment, time, dia) { return results; } + +function iobCalc(treatment, time, dia, profile) { + + if (!treatment.insulin) return {}; + + var curve = 'bilinear'; + + if (profile.curve !== undefined) { + curve = profile.curve.toLowerCase(); + } + + var curveDefaults = { + 'bilinear': { + requireLongDia: false + }, + 'rapid-acting': { + requireLongDia: true, + peak: 75, + tdMin: 300 + }, + 'ultra-rapid': { + requireLongDia: true, + peak: 55, + tdMin: 300 + }, + }; + + if (!(curve in curveDefaults)) { + console.error('Unsupported curve function: "' + curve + '". Supported curves: "bilinear", "rapid-acting" (Novolog, Novorapid, Humalog, Apidra) and "ultra-rapid" (Fiasp). Defaulting to "rapid-acting".'); + curve = 'bilinear'; + } + + if (curve == 'bilinear') { + return iobCalcBiLinear(treatment, time, dia); + } + + var defaults = curveDefaults[curve]; + + var usePeakTime = false; + + var td = dia * 60; + + if (defaults.requireLongDia && dia < 5) { + console.error('Pump DIA must be set to 5 hours or more with the new curves, please adjust your pump. Defaulting to 5 hour DIA.'); + td = 300; + } + + var tp = defaults.peak; + + if (profile.useCustomPeakTime && profile.insulinPeakTime !== undefined) { + if (profile.insulinPeakTime < 35 || profile.insulinPeakTime > 120) { + console.error('Insulin Peak Time is only supported for values between 35 to 120 minutes'); + + } else { + tp = profile.insulinPeakTime; + } + } + + if (typeof time === 'undefined') { + time = timeRef; + } + + var bolusTime = new Date(treatment.date); + var t = Math.round((time - bolusTime) / 1000 / 60); + + var activityContrib = 0; + var iobContrib = 0; + var biobContrib = 0; + + // force the IOB to 0 if over 5 hours have passed + if (t < td) { + + var tau = tp * (1 - tp / td) / (1 - 2 * tp / td); + var a = 2 * tau / td; + var S = 1 / (1 - a + (1 + a) * Math.exp(-td / tau)); + + activityContrib = treatment.insulin * (S / Math.pow(tau, 2)) * t * (1 - t / td) * Math.exp(-t / tau); + iobContrib = treatment.insulin * (1 - S * (1 - a) * ((Math.pow(t, 2) / (tau * td * (1 - a)) - t / tau - 1) * Math.exp(-t / tau) + 1)); + // calculate bolus snooze insulin in the same pass + t = t * profile.bolussnooze_dia_divisor; + var biobContrib = treatment.insulin * (1 - S * (1 - a) * ((Math.pow(t, 2) / (tau * td * (1 - a)) - t / tau - 1) * Math.exp(-t / tau) + 1)); + + //console.error('DIA: ' + dia + ' t: ' + t + ' td: ' + td + ' tp: ' + tp + ' tau: ' + tau + ' a: ' + a + ' S: ' + S + ' activityContrib: ' + activityContrib + ' iobContrib: ' + iobContrib); + + } + + results = { + iobContrib: iobContrib, + activityContrib: activityContrib, + biobContrib: biobContrib + }; + + return results; +} + exports = module.exports = iobCalc; diff --git a/lib/iob/total.js b/lib/iob/total.js index d21d89d36..2c01c5a52 100644 --- a/lib/iob/total.js +++ b/lib/iob/total.js @@ -1,4 +1,5 @@ function iobTotal(opts, time) { + var now = time.getTime(); var iobCalc = opts.calculate; var treatments = opts.treatments; @@ -21,7 +22,7 @@ function iobTotal(opts, time) { var dia = profile_data.dia; var dia_ago = now - profile_data.dia*60*60*1000; // tIOB = total IOB - var tIOB = iobCalc(treatment, time, dia); + var tIOB = iobCalc(treatment, time, dia, profile_data); 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 twice as fast @@ -32,10 +33,14 @@ function iobTotal(opts, time) { if (treatment.insulin > profile_data.current_basal/1.5 && treatment.started_at) { //default bolussnooze_dia_divisor is 2, for 2x speed bolus snooze // bIOB = bolus IOB - var bIOB = iobCalc(treatment, time, dia / profile_data.bolussnooze_dia_divisor); - //console.log(treatment); - //console.log(bIOB); - if (bIOB && bIOB.iobContrib) bolussnooze += bIOB.iobContrib; + if (tIOB.biobContrib !== undefined) { + bolussnooze += tIOB.biobContrib; + } else { + var bIOB = iobCalc(treatment, time, dia / profile_data.bolussnooze_dia_divisor, profile_data); + //console.log(treatment); + //console.log(bIOB); + if (bIOB && bIOB.iobContrib) bolussnooze += bIOB.iobContrib; + } } else { // track microBolus IOB, but also count it toward basaliob and hightempinsulin if (treatment.insulin <= profile_data.current_basal/1.5 && treatment.started_at) { @@ -47,7 +52,7 @@ function iobTotal(opts, time) { } } // aIOB = basal IOB - var aIOB = iobCalc(treatment, time, dia); + var aIOB = tIOB; // iobCalc(treatment, time, dia, profile_data); if (aIOB && aIOB.iobContrib) basaliob += aIOB.iobContrib; if (treatment.insulin) { if(treatment.date > dia_ago && treatment.date <= now) { @@ -61,18 +66,19 @@ function iobTotal(opts, time) { } }); - return { - iob: Math.round( iob * 1000 ) / 1000, - activity: Math.round( activity * 10000 ) / 10000, - bolussnooze: Math.round( bolussnooze * 1000 ) / 1000, - basaliob: Math.round( basaliob * 1000 ) / 1000, - netbasalinsulin: Math.round( netbasalinsulin * 1000 ) / 1000, - hightempinsulin: Math.round( hightempinsulin * 1000 ) / 1000, - microBolusInsulin: Math.round( microBolusInsulin * 1000 ) / 1000, - microBolusIOB: Math.round( microBolusIOB * 1000 ) / 1000, + var rval = { + iob: Math.round(iob * 1000) / 1000, + activity: Math.round(activity * 10000) / 10000, + bolussnooze: Math.round(bolussnooze * 1000) / 1000, + basaliob: Math.round(basaliob * 1000) / 1000, + netbasalinsulin: Math.round(netbasalinsulin * 1000) / 1000, + hightempinsulin: Math.round(hightempinsulin * 1000) / 1000, + microBolusInsulin: Math.round(microBolusInsulin * 1000) / 1000, + microBolusIOB: Math.round(microBolusIOB * 1000) / 1000, time: time }; + + return rval; } exports = module.exports = iobTotal; - diff --git a/lib/profile/index.js b/lib/profile/index.js index 73789eaec..9f6932a92 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -34,6 +34,9 @@ function defaults ( ) { , enableSMB_with_COB: false // enable supermicrobolus while COB is positive , enableSMB_with_temptarget: false // enable supermicrobolus for eating soon temp targets , enableSMB_after_carbs: false // enable supermicrobolus for 6h after carbs, even with 0 COB + , curve: "bilinear" + , useCustomPeakTime: false + , insulinPeakTime: 75 }; return profile; } diff --git a/tests/iob.test.js b/tests/iob.test.js index 33075ef95..801e9cf62 100644 --- a/tests/iob.test.js +++ b/tests/iob.test.js @@ -4,356 +4,953 @@ require('should'); var moment = require('moment'); -describe('IOB', function ( ) { - - it('should calculate IOB', function() { - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 1, 'minutes': 0}]; - - var now = Date.now() - , timestamp = new Date(now).toISOString() - , inputs = { - clock: timestamp - , history: [{ - _type: 'Bolus' - , amount: 1 - , timestamp: timestamp - }] - , profile: { - dia: 3, bolussnooze_dia_divisor: 2, basalprofile: basalprofile, current_basal: 1 } - - }; - - var rightAfterBolus = require('../lib/iob')(inputs)[0]; - rightAfterBolus.iob.should.equal(1); - rightAfterBolus.bolussnooze.should.equal(1); - - var hourLaterInputs = inputs; - hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - hourLater.iob.should.be.lessThan(1); - hourLater.bolussnooze.should.be.lessThan(.5); - hourLater.iob.should.be.greaterThan(0); - - var afterDIAInputs = inputs; - afterDIAInputs.clock = new Date(now + (3 * 60 * 60 * 1000)).toISOString(); - var afterDIA = require('../lib/iob')(afterDIAInputs)[0]; - - afterDIA.iob.should.equal(0); - afterDIA.bolussnooze.should.equal(0); - }); - - it('should snooze fast if bolussnooze_dia_divisor is high', function() { - - var now = Date.now() - , timestamp = new Date(now).toISOString() - , inputs = { - clock: timestamp - , history: [{ - _type: 'Bolus' - , amount: 1 - , timestamp: timestamp - }] - , profile: { - dia: 3 - , bolussnooze_dia_divisor: 10 - } - }; - - var snoozeInputs = inputs; - snoozeInputs.clock = new Date(now + (20 * 60 * 1000)).toISOString(); - var snooze = require('../lib/iob')(snoozeInputs)[0]; - snooze.bolussnooze.should.equal(0); - }); - - it('should calculate IOB with Temp Basals', function() { - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 1, 'minutes': 0}]; - var now = Date.now() - , timestamp = new Date(now).toISOString() - , timestamp30mAgo = new Date(now - (30 * 60 * 1000)).toISOString() - , timestamp60mAgo = new Date(now - (60 * 60 * 1000)).toISOString() - , inputs = {clock: timestamp, - history: [{_type: 'TempBasalDuration','duration (min)': 30, date: timestamp60mAgo} - , {_type: 'TempBasal', rate: 2, date: timestamp60mAgo, timestamp: timestamp60mAgo} - , {_type: 'TempBasal', rate: 2, date: timestamp30mAgo, timestamp: timestamp30mAgo} - , {_type: 'TempBasalDuration','duration (min)': 30, date: timestamp}] - , profile: { dia: 3, current_basal: 1, bolussnooze_dia_divisor: 2, 'basalprofile': basalprofile} - }; - - var iobInputs = inputs; - iobInputs.clock = timestamp - var iobNow = require('../lib/iob')(iobInputs)[0]; - - //console.log(iobNow); - iobNow.iob.should.be.lessThan(1); - iobNow.iob.should.be.greaterThan(0.5); - }); - - it('should calculate IOB with Temp Basals and a basal profile', function() { - - var startingPoint = moment('2016-06-13 01:00:00.000'); - var timestamp = startingPoint.format(); - var timestampEarly = startingPoint.subtract(30,'minutes').format(); - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 2, 'minutes': 0}, - {'i': 1, 'start': '01:00:00', 'rate': 1, 'minutes': 60 }]; - - var inputs = {clock: timestamp, - history: [{_type: 'TempBasalDuration','duration (min)': 30, date: timestampEarly} - , {_type: 'TempBasal', rate: 2, date: timestampEarly, timestamp: timestampEarly} - , {_type: 'TempBasal', rate: 2, date: timestamp, timestamp: timestamp} - , {_type: 'TempBasalDuration','duration (min)': 30, date: timestamp}] - , profile: { dia: 3, bolussnooze_dia_divisor: 2, basalprofile: basalprofile} - }; - - var hourLaterInputs = inputs; - hourLaterInputs.clock = moment('2016-06-13 01:30:00.000'); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - hourLater.iob.should.be.lessThan(0.5); - hourLater.iob.should.be.greaterThan(0.4); - }); - - it('should calculate IOB with Temp Basals that overlap midnight and a basal profile', function() { - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 2, 'minutes': 0}, - {'i': 1, 'start': '00:15:00', 'rate': 1, 'minutes': 15 }, - {'i': 2, 'start': '00:45:00', 'rate': 0.5, 'minutes': 45 }]; - - var startingPoint = moment('2016-06-13 00:15:00.000'); - var timestamp = startingPoint.format(); - var timestampEarly = startingPoint.subtract(30,'minutes').format() - , inputs = {clock: timestamp, - history: [{_type: 'TempBasalDuration','duration (min)': 30, date: timestampEarly} - , {_type: 'TempBasal', rate: 2, date: timestampEarly, timestamp: timestampEarly} - , {_type: 'TempBasal', rate: 2, date: timestamp, timestamp: timestamp} - , {_type: 'TempBasalDuration','duration (min)': 30, date: timestamp}] - , profile: { dia: 3, current_basal: 0.1, bolussnooze_dia_divisor: 2, basalprofile: basalprofile} - }; - - var hourLaterInputs = inputs; - hourLaterInputs.clock = moment('2016-06-13 00:45:00.000'); //new Date(now + (30 * 60 * 1000)).toISOString(); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - - hourLater.iob.should.be.lessThan(0.8); - hourLater.iob.should.be.greaterThan(0.7); - }); - - it('should calculate IOB with Temp Basals that overlap each other', function() { - - var nowDate = new Date(); - var now = Date.now(); - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 1, 'minutes': 0}]; - - var startingPoint = moment('2016-06-13 00:30:00.000'); - var timestampEarly = moment('2016-06-13 00:30:00.000').subtract(30,'minutes'); - var timestampEarly2 = moment('2016-06-13 00:30:00.000').subtract(29,'minutes'); - var timestampEarly3 = moment('2016-06-13 00:30:00.000').subtract(28,'minutes'); - - var timestamp = startingPoint; - var inputs = {clock: timestamp, - history: [ - {_type: 'TempBasalDuration','duration (min)': 30, date: timestampEarly.unix()} - , {_type: 'TempBasal', rate: 2, date: timestampEarly.unix(), timestamp: timestampEarly.format()} - , {_type: 'TempBasalDuration','duration (min)': 30, date: timestampEarly2.unix()} - , {_type: 'TempBasal', rate: 2, date: timestampEarly2.unix(), timestamp: timestampEarly2.format()} - , {_type: 'TempBasalDuration','duration (min)': 30, date: timestampEarly3.unix()} - , {_type: 'TempBasal', rate: 2, date: timestampEarly3.unix(), timestamp: timestampEarly3.format()} - , {_type: 'TempBasal', rate: 2, date: timestamp.unix(), timestamp: timestamp.format()} - , {_type: 'TempBasalDuration','duration (min)': 30, date: timestamp.unix()}] - , profile: { dia: 3, current_basal: 0.1, bolussnooze_dia_divisor: 2, basalprofile: basalprofile} - }; - - var hourLaterInputs = inputs; - hourLaterInputs.clock = moment('2016-06-13 00:30:00.000'); //new Date(now + (30 * 60 * 1000)).toISOString(); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - - hourLater.iob.should.be.lessThan(0.5); - hourLater.iob.should.be.greaterThan(0.45); - }); - it('should calculate IOB with Temp Basals that overlap midnight and a basal profile, part deux', function() { - - var nowDate = new Date(); - var now = Date.now(); - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 2, 'minutes': 0}, - {'i': 1, 'start': '00:15:00', 'rate': 0.1, 'minutes': 15 }, - {'i': 1, 'start': '00:30:00', 'rate': 2, 'minutes': 30 }, - {'i': 1, 'start': '00:45:00', 'rate': 0.1, 'minutes': 45 }]; - - var startingPoint = moment('2016-06-13 23:45:00.000'); - var timestamp = startingPoint.format(); - var timestampEarly = startingPoint.subtract(30,'minutes').format() - , inputs = {clock: timestamp, - history: [{_type: 'TempBasalDuration','duration (min)': 60, date: timestamp} - , {_type: 'TempBasal', rate: 2, date: timestamp, timestamp: timestamp} ] - , profile: { dia: 3, current_basal: 0.1, bolussnooze_dia_divisor: 2, basalprofile: basalprofile} - }; - - var hourLaterInputs = inputs; - hourLaterInputs.clock = moment('2016-06-14 00:45:00.000'); //new Date(now + (30 * 60 * 1000)).toISOString(); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - - hourLater.iob.should.be.lessThan(1); - hourLater.iob.should.be.greaterThan(0.8); - }); - - - it('should not report negative IOB with Temp Basals and a basal profile with drastic changes', function() { - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 0.1, 'minutes': 0}, - {'i': 1, 'start': '00:30:00', 'rate': 2, 'minutes': 30 }]; - - var startingPoint = new Date('2016-06-13 00:00:00.000'); - var startingPoint2 = new Date('2016-06-13 00:30:00.000'); - var endPoint = new Date('2016-06-13 01:00:00.000'); - - var inputs = {clock: endPoint, - history: [{_type: 'TempBasalDuration','duration (min)': 30, date: startingPoint} - , {_type: 'TempBasal', rate: 0.1, date: startingPoint, timestamp: startingPoint} - , {_type: 'TempBasal', rate: 2, date: startingPoint2, timestamp: startingPoint2} - , {_type: 'TempBasalDuration','duration (min)': 30, date: startingPoint2}] - , profile: { dia: 3, current_basal: 2, bolussnooze_dia_divisor: 2, 'basalprofile': basalprofile} - }; - - var hourLaterInputs = inputs; - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - hourLater.iob.should.equal(0); - }); - - it('should calculate IOB with Temp Basal events that overlap', function() { - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 1, 'minutes': 0}]; - - var now = Date.now() - , timestamp30mAgo = new Date(now - (30 * 60 * 1000)).toISOString() - , timestamp31mAgo = new Date(now - (31 * 60 * 1000)).toISOString() - , inputs = {clock: timestamp30mAgo, - history: [{_type: 'TempBasalDuration','duration (min)': 30, date: timestamp31mAgo} - ,{_type: 'TempBasal', rate: 2, date: timestamp31mAgo, timestamp: timestamp31mAgo} - ,{_type: 'TempBasal', rate: 2, date: timestamp30mAgo, timestamp: timestamp30mAgo} - ,{_type: 'TempBasalDuration','duration (min)': 30, date: timestamp30mAgo}] - , profile: { dia: 3, current_basal: 1, 'basalprofile': basalprofile} - }; - - var hourLaterInputs = inputs; - hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - - hourLater.iob.should.be.lessThan(1); - hourLater.iob.should.be.greaterThan(0); - - }); - - it('should calculate IOB with Temp Basals that are lower than base rate', function() { - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 2, 'minutes': 0}]; - - var now = Date.now() - , timestamp = new Date(now).toISOString() - , timestampEarly = new Date(now - (30 * 60 * 1000)).toISOString() - , inputs = {clock: timestamp, - history: [{_type: 'TempBasalDuration','duration (min)': 30, date: timestampEarly} - , {_type: 'TempBasal', rate: 1, date: timestampEarly, timestamp: timestampEarly} - , {_type: 'TempBasal', rate: 1, date: timestamp, timestamp: timestamp} - , {_type: 'TempBasalDuration','duration (min)': 30, date: timestamp}] - , profile: { dia: 3, current_basal: 2, bolussnooze_dia_divisor: 2, 'basalprofile': basalprofile} - }; - - var hourLaterInputs = inputs; - hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - - hourLater.iob.should.be.lessThan(0); - hourLater.iob.should.be.greaterThan(-1); - - }); - - it('should show 0 IOB with Temp Basals if duration is not found', function() { - - var now = Date.now() - , timestamp = new Date(now).toISOString() - , timestampEarly = new Date(now - (60 * 60 * 1000)).toISOString() - , inputs = { - clock: timestamp - , history: [{_type: 'TempBasal', rate: 2, date: timestamp, timestamp: timestamp}] - , profile: {dia: 3, current_basal: 1, bolussnooze_dia_divisor: 2} - }; - - var hourLaterInputs = inputs; - hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - - hourLater.iob.should.equal(0); - }); - - it('should show 0 IOB with Temp Basals if basal is percentage based', function() { - - var now = Date.now() - , timestamp = new Date(now).toISOString() - , timestampEarly = new Date(now - (60 * 60 * 1000)).toISOString() - , inputs = { - clock: timestamp - , history: [{_type: 'TempBasal', temp: 'percent', rate: 2, date: timestamp, timestamp: timestamp}, - {_type: 'TempBasalDuration','duration (min)': 30, date: timestamp}] - , profile: {dia: 3,current_basal: 1, bolussnooze_dia_divisor: 2} - }; - - - var hourLaterInputs = inputs; - hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - - hourLater.iob.should.equal(0); - }); - - - it('should calculate IOB using a 4 hour duration', function() { - - var basalprofile = [{'i': 0, 'start': '00:00:00', 'rate': 1, 'minutes': 0}]; - - var now = Date.now() - , timestamp = new Date(now).toISOString() - , inputs = { - clock: timestamp - , history: [{ - _type: 'Bolus' - , amount: 1 - , timestamp: timestamp - }] - , profile: { - dia: 4 - , bolussnooze_dia_divisor: 2 - , basalprofile: basalprofile - , current_basal: 1 - } - - }; - - var rightAfterBolus = require('../lib/iob')(inputs)[0]; - //console.log(rightAfterBolus); - rightAfterBolus.iob.should.equal(1); - rightAfterBolus.bolussnooze.should.equal(1); - - var hourLaterInputs = inputs; - hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); - var hourLater = require('../lib/iob')(hourLaterInputs)[0]; - hourLater.iob.should.be.lessThan(1); - hourLater.bolussnooze.should.be.lessThan(.5); - hourLater.iob.should.be.greaterThan(0); - - var after3hInputs = inputs; - after3hInputs.clock = new Date(now + (3 * 60 * 60 * 1000)).toISOString(); - var after3h = require('../lib/iob')(after3hInputs)[0]; - after3h.iob.should.be.greaterThan(0); - - var after4hInputs = inputs; - after4hInputs.clock = new Date(now + (4 * 60 * 60 * 1000)).toISOString(); - var after4h = require('../lib/iob')(after4hInputs)[0]; - after4h.iob.should.equal(0); - - }); - - -}); +describe('IOB', function() { + + it('should calculate IOB', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'Bolus', + amount: 2, + timestamp: timestamp + }], + profile: { + dia: 3, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile, + current_basal: 1 + } + + }; + + var rightAfterBolus = require('../lib/iob')(inputs)[0]; + rightAfterBolus.iob.should.equal(2); + rightAfterBolus.bolussnooze.should.equal(2); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.be.lessThan(1.45); + hourLater.bolussnooze.should.be.lessThan(.5); + hourLater.iob.should.be.greaterThan(0); + hourLater.activity.should.be.greaterThan(0.01); + hourLater.activity.should.be.lessThan(0.02); + + var afterDIAInputs = inputs; + afterDIAInputs.clock = new Date(now + (3 * 60 * 60 * 1000)).toISOString(); + var afterDIA = require('../lib/iob')(afterDIAInputs)[0]; + + afterDIA.iob.should.equal(0); + afterDIA.bolussnooze.should.equal(0); + }); + + it('should calculate IOB with Ultra-fast curve', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'Bolus', + amount: 2, + timestamp: timestamp + }], + profile: { + dia: 5, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile, + current_basal: 1, + curve: 'ultra-rapid' + } + }; + + var rightAfterBolus = require('../lib/iob')(inputs)[0]; + + rightAfterBolus.iob.should.equal(2); + rightAfterBolus.bolussnooze.should.equal(2); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.be.lessThan(1.6); + hourLater.iob.should.be.greaterThan(1.3); + + hourLater.bolussnooze.should.be.lessThan(1.7); + hourLater.iob.should.be.greaterThan(0); + hourLater.activity.should.be.greaterThan(0.006); + hourLater.activity.should.be.lessThan(0.015); + + var afterDIAInputs = inputs; + afterDIAInputs.clock = new Date(now + (5 * 60 * 60 * 1000)).toISOString(); + var afterDIA = require('../lib/iob')(afterDIAInputs)[0]; + afterDIA.iob.should.equal(0); + afterDIA.bolussnooze.should.equal(0); + }); + + + it('should calculate IOB with Ultra-fast peak setting of 55', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'Bolus', + amount: 1, + timestamp: timestamp + }], + profile: { + dia: 5, + insulinPeakTime: 55, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile, + current_basal: 1, + curve: 'ultra-rapid' + } + }; + + var rightAfterBolus = require('../lib/iob')(inputs)[0]; + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolussnooze.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.be.lessThan(0.75); + hourLater.bolussnooze.should.be.lessThan(0.75); + hourLater.iob.should.be.greaterThan(0); + hourLater.activity.should.be.greaterThan(0.0065); + hourLater.activity.should.be.lessThan(0.008); + + var afterDIAInputs = inputs; + afterDIAInputs.clock = new Date(now + (5 * 60 * 60 * 1000)).toISOString(); + var afterDIA = require('../lib/iob')(afterDIAInputs)[0]; + + afterDIA.iob.should.equal(0); + afterDIA.bolussnooze.should.equal(0); + }); + + it('should calculate IOB with Ultra-fast curve peak setting of 65', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'Bolus', + amount: 1, + timestamp: timestamp + }], + profile: { + dia: 5, + insulinPeakTime: 65, + useCustomPeakTime: true, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile, + current_basal: 1, + curve: 'ultra-rapid' + } + }; + + var rightAfterBolus = require('../lib/iob')(inputs)[0]; + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolussnooze.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.be.lessThan(0.77); + hourLater.bolussnooze.should.be.lessThan(0.36); + hourLater.iob.should.be.greaterThan(0.72); + hourLater.bolussnooze.should.be.greaterThan(0.354); + + hourLater.activity.should.be.greaterThan(0.0055); + hourLater.activity.should.be.lessThan(0.007); + + var afterDIAInputs = inputs; + afterDIAInputs.clock = new Date(now + (5 * 60 * 60 * 1000)).toISOString(); + var afterDIA = require('../lib/iob')(afterDIAInputs)[0]; + + afterDIA.iob.should.equal(0); + afterDIA.bolussnooze.should.equal(0); + }); + + it('should calculate IOB with Ultra-rapid curve peak setting of 75', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'Bolus', + amount: 1, + timestamp: timestamp + }], + profile: { + dia: 5, + insulinPeakTime: 75, + useCustomPeakTime: true, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile, + current_basal: 1, + curve: 'ultra-rapid' + } + }; + + var rightAfterBolus = require('../lib/iob')(inputs)[0]; + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolussnooze.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.be.lessThan(0.81); + hourLater.bolussnooze.should.be.lessThan(0.5); + hourLater.iob.should.be.greaterThan(0.76); + hourLater.bolussnooze.should.be.greaterThan(0.40); + + hourLater.iob.should.be.greaterThan(0); + hourLater.activity.should.be.greaterThan(0.0047); + hourLater.activity.should.be.lessThan(0.007); + + var afterDIAInputs = inputs; + afterDIAInputs.clock = new Date(now + (5 * 60 * 60 * 1000)).toISOString(); + var afterDIA = require('../lib/iob')(afterDIAInputs)[0]; + + afterDIA.iob.should.equal(0); + afterDIA.bolussnooze.should.equal(0); + }); + + it('should calculate IOB with Ultra-rapid curve peak setting of 44 and DIA = 6', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'Bolus', + amount: 1, + timestamp: timestamp + }], + profile: { + dia: 6, + insulinPeakTime: 44, + useCustomPeakTime: true, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile, + current_basal: 1, + curve: 'ultra-rapid' + } + }; + + var rightAfterBolus = require('../lib/iob')(inputs)[0]; + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolussnooze.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.be.lessThan(0.59); + hourLater.bolussnooze.should.be.lessThan(0.23); + + hourLater.iob.should.be.greaterThan(0.57); + hourLater.bolussnooze.should.be.greaterThan(0.21); + + hourLater.activity.should.be.greaterThan(0.007); + hourLater.activity.should.be.lessThan(0.0085); + + var afterDIAInputs = inputs; + afterDIAInputs.clock = new Date(now + (6 * 60 * 60 * 1000)).toISOString(); + var afterDIA = require('../lib/iob')(afterDIAInputs)[0]; + + afterDIA.iob.should.equal(0); + afterDIA.bolussnooze.should.equal(0); + }); + + + + it('should calculate IOB with Rapid-acting', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'Bolus', + amount: 1, + timestamp: timestamp + }], + profile: { + dia: 5, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile, + current_basal: 1, + curve: 'rapid-acting' + } + }; + + var rightAfterBolus = require('../lib/iob')(inputs)[0]; + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolussnooze.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.be.lessThan(0.8); + hourLater.bolussnooze.should.be.lessThan(.8); + hourLater.iob.should.be.greaterThan(0); + + var afterDIAInputs = inputs; + afterDIAInputs.clock = new Date(now + (5 * 60 * 60 * 1000)).toISOString(); + var afterDIA = require('../lib/iob')(afterDIAInputs)[0]; + + afterDIA.iob.should.equal(0); + afterDIA.bolussnooze.should.equal(0); + }); + + + it('should snooze fast if bolussnooze_dia_divisor is high', function() { + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'Bolus', + amount: 1, + timestamp: timestamp + }], + profile: { + dia: 3, + bolussnooze_dia_divisor: 10 + } + }; + + var snoozeInputs = inputs; + snoozeInputs.clock = new Date(now + (20 * 60 * 1000)).toISOString(); + var snooze = require('../lib/iob')(snoozeInputs)[0]; + snooze.bolussnooze.should.equal(0); + }); + + it('should calculate IOB with Temp Basals', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + var now = Date.now(), + timestamp = new Date(now).toISOString(), + timestamp30mAgo = new Date(now - (30 * 60 * 1000)).toISOString(), + timestamp60mAgo = new Date(now - (60 * 60 * 1000)).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestamp60mAgo + }, { + _type: 'TempBasal', + rate: 2, + date: timestamp60mAgo, + timestamp: timestamp60mAgo + }, { + _type: 'TempBasal', + rate: 2, + date: timestamp30mAgo, + timestamp: timestamp30mAgo + }, { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestamp + }], + profile: { + dia: 3, + current_basal: 1, + bolussnooze_dia_divisor: 2, + 'basalprofile': basalprofile + } + }; + + var iobInputs = inputs; + iobInputs.clock = timestamp + var iobNow = require('../lib/iob')(iobInputs)[0]; + + //console.log(iobNow); + iobNow.iob.should.be.lessThan(1); + iobNow.iob.should.be.greaterThan(0.5); + }); + + it('should calculate IOB with Temp Basals and a basal profile', function() { + + var startingPoint = moment('2016-06-13 01:00:00.000'); + var timestamp = startingPoint.format(); + var timestampEarly = startingPoint.subtract(30, 'minutes').format(); + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 2, + 'minutes': 0 + }, + { + 'i': 1, + 'start': '01:00:00', + 'rate': 1, + 'minutes': 60 + } + ]; + + var inputs = { + clock: timestamp, + history: [{ + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestampEarly + }, { + _type: 'TempBasal', + rate: 2, + date: timestampEarly, + timestamp: timestampEarly + }, { + _type: 'TempBasal', + rate: 2, + date: timestamp, + timestamp: timestamp + }, { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestamp + }], + profile: { + dia: 3, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile + } + }; + + var hourLaterInputs = inputs; + hourLaterInputs.clock = moment('2016-06-13 01:30:00.000'); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.be.lessThan(0.5); + hourLater.iob.should.be.greaterThan(0.4); + }); + + it('should calculate IOB with Temp Basals that overlap midnight and a basal profile', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 2, + 'minutes': 0 + }, + { + 'i': 1, + 'start': '00:15:00', + 'rate': 1, + 'minutes': 15 + }, + { + 'i': 2, + 'start': '00:45:00', + 'rate': 0.5, + 'minutes': 45 + } + ]; + + var startingPoint = moment('2016-06-13 00:15:00.000'); + var timestamp = startingPoint.format(); + var timestampEarly = startingPoint.subtract(30, 'minutes').format(), + inputs = { + clock: timestamp, + history: [{ + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestampEarly + }, { + _type: 'TempBasal', + rate: 2, + date: timestampEarly, + timestamp: timestampEarly + }, { + _type: 'TempBasal', + rate: 2, + date: timestamp, + timestamp: timestamp + }, { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestamp + }], + profile: { + dia: 3, + current_basal: 0.1, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile + } + }; + + var hourLaterInputs = inputs; + hourLaterInputs.clock = moment('2016-06-13 00:45:00.000'); //new Date(now + (30 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + + hourLater.iob.should.be.lessThan(0.8); + hourLater.iob.should.be.greaterThan(0.7); + }); + + it('should calculate IOB with Temp Basals that overlap each other', function() { + + var nowDate = new Date(); + var now = Date.now(); + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var startingPoint = moment('2016-06-13 00:30:00.000'); + var timestampEarly = moment('2016-06-13 00:30:00.000').subtract(30, 'minutes'); + var timestampEarly2 = moment('2016-06-13 00:30:00.000').subtract(29, 'minutes'); + var timestampEarly3 = moment('2016-06-13 00:30:00.000').subtract(28, 'minutes'); + + var timestamp = startingPoint; + var inputs = { + clock: timestamp, + history: [{ + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestampEarly.unix() + }, { + _type: 'TempBasal', + rate: 2, + date: timestampEarly.unix(), + timestamp: timestampEarly.format() + }, { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestampEarly2.unix() + }, { + _type: 'TempBasal', + rate: 2, + date: timestampEarly2.unix(), + timestamp: timestampEarly2.format() + }, { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestampEarly3.unix() + }, { + _type: 'TempBasal', + rate: 2, + date: timestampEarly3.unix(), + timestamp: timestampEarly3.format() + }, { + _type: 'TempBasal', + rate: 2, + date: timestamp.unix(), + timestamp: timestamp.format() + }, { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestamp.unix() + }], + profile: { + dia: 3, + current_basal: 0.1, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile + } + }; + + var hourLaterInputs = inputs; + hourLaterInputs.clock = moment('2016-06-13 00:30:00.000'); //new Date(now + (30 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + + hourLater.iob.should.be.lessThan(0.5); + hourLater.iob.should.be.greaterThan(0.45); + }); + it('should calculate IOB with Temp Basals that overlap midnight and a basal profile, part deux', function() { + + var nowDate = new Date(); + var now = Date.now(); + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 2, + 'minutes': 0 + }, + { + 'i': 1, + 'start': '00:15:00', + 'rate': 0.1, + 'minutes': 15 + }, + { + 'i': 1, + 'start': '00:30:00', + 'rate': 2, + 'minutes': 30 + }, + { + 'i': 1, + 'start': '00:45:00', + 'rate': 0.1, + 'minutes': 45 + } + ]; + + var startingPoint = moment('2016-06-13 23:45:00.000'); + var timestamp = startingPoint.format(); + var timestampEarly = startingPoint.subtract(30, 'minutes').format(), + inputs = { + clock: timestamp, + history: [{ + _type: 'TempBasalDuration', + 'duration (min)': 60, + date: timestamp + }, { + _type: 'TempBasal', + rate: 2, + date: timestamp, + timestamp: timestamp + }], + profile: { + dia: 3, + current_basal: 0.1, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile + } + }; + + var hourLaterInputs = inputs; + hourLaterInputs.clock = moment('2016-06-14 00:45:00.000'); //new Date(now + (30 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + + hourLater.iob.should.be.lessThan(1); + hourLater.iob.should.be.greaterThan(0.8); + }); + + + it('should not report negative IOB with Temp Basals and a basal profile with drastic changes', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 0.1, + 'minutes': 0 + }, + { + 'i': 1, + 'start': '00:30:00', + 'rate': 2, + 'minutes': 30 + } + ]; + + var startingPoint = new Date('2016-06-13 00:00:00.000'); + var startingPoint2 = new Date('2016-06-13 00:30:00.000'); + var endPoint = new Date('2016-06-13 01:00:00.000'); + + var inputs = { + clock: endPoint, + history: [{ + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: startingPoint + }, { + _type: 'TempBasal', + rate: 0.1, + date: startingPoint, + timestamp: startingPoint + }, { + _type: 'TempBasal', + rate: 2, + date: startingPoint2, + timestamp: startingPoint2 + }, { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: startingPoint2 + }], + profile: { + dia: 3, + current_basal: 2, + bolussnooze_dia_divisor: 2, + 'basalprofile': basalprofile + } + }; + + var hourLaterInputs = inputs; + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.equal(0); + }); + + it('should calculate IOB with Temp Basal events that overlap', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp30mAgo = new Date(now - (30 * 60 * 1000)).toISOString(), + timestamp31mAgo = new Date(now - (31 * 60 * 1000)).toISOString(), + inputs = { + clock: timestamp30mAgo, + history: [{ + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestamp31mAgo + }, { + _type: 'TempBasal', + rate: 2, + date: timestamp31mAgo, + timestamp: timestamp31mAgo + }, { + _type: 'TempBasal', + rate: 2, + date: timestamp30mAgo, + timestamp: timestamp30mAgo + }, { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestamp30mAgo + }], + profile: { + dia: 3, + current_basal: 1, + 'basalprofile': basalprofile + } + }; + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + + hourLater.iob.should.be.lessThan(1); + hourLater.iob.should.be.greaterThan(0); + + }); + + it('should calculate IOB with Temp Basals that are lower than base rate', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 2, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + timestampEarly = new Date(now - (30 * 60 * 1000)).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestampEarly + }, { + _type: 'TempBasal', + rate: 1, + date: timestampEarly, + timestamp: timestampEarly + }, { + _type: 'TempBasal', + rate: 1, + date: timestamp, + timestamp: timestamp + }, { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestamp + }], + profile: { + dia: 3, + current_basal: 2, + bolussnooze_dia_divisor: 2, + 'basalprofile': basalprofile + } + }; + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + + hourLater.iob.should.be.lessThan(0); + hourLater.iob.should.be.greaterThan(-1); + + }); + + it('should show 0 IOB with Temp Basals if duration is not found', function() { + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + timestampEarly = new Date(now - (60 * 60 * 1000)).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'TempBasal', + rate: 2, + date: timestamp, + timestamp: timestamp + }], + profile: { + dia: 3, + current_basal: 1, + bolussnooze_dia_divisor: 2 + } + }; + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + + hourLater.iob.should.equal(0); + }); + + it('should show 0 IOB with Temp Basals if basal is percentage based', function() { + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + timestampEarly = new Date(now - (60 * 60 * 1000)).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'TempBasal', + temp: 'percent', + rate: 2, + date: timestamp, + timestamp: timestamp + }, + { + _type: 'TempBasalDuration', + 'duration (min)': 30, + date: timestamp + } + ], + profile: { + dia: 3, + current_basal: 1, + bolussnooze_dia_divisor: 2 + } + }; + + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + + hourLater.iob.should.equal(0); + }); + + + it('should calculate IOB using a 4 hour duration', function() { + + var basalprofile = [{ + 'i': 0, + 'start': '00:00:00', + 'rate': 1, + 'minutes': 0 + }]; + + var now = Date.now(), + timestamp = new Date(now).toISOString(), + inputs = { + clock: timestamp, + history: [{ + _type: 'Bolus', + amount: 1, + timestamp: timestamp + }], + profile: { + dia: 4, + bolussnooze_dia_divisor: 2, + basalprofile: basalprofile, + current_basal: 1 + } + + }; + + var rightAfterBolus = require('../lib/iob')(inputs)[0]; + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolussnooze.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs)[0]; + hourLater.iob.should.be.lessThan(1); + hourLater.bolussnooze.should.be.lessThan(.5); + hourLater.iob.should.be.greaterThan(0); + + var after3hInputs = inputs; + after3hInputs.clock = new Date(now + (3 * 60 * 60 * 1000)).toISOString(); + var after3h = require('../lib/iob')(after3hInputs)[0]; + after3h.iob.should.be.greaterThan(0); + + var after4hInputs = inputs; + after4hInputs.clock = new Date(now + (4 * 60 * 60 * 1000)).toISOString(); + var after4h = require('../lib/iob')(after4hInputs)[0]; + after4h.iob.should.equal(0); + + }); + + +}); \ No newline at end of file From 0859697c56be4d6a6f28c48a1f3638cff7b10693 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Aug 2017 10:39:51 -0700 Subject: [PATCH 022/215] Speed up COB calculation by only converting pumphistory to treatments once (#603) * get treatments from pumphistory once, not every time we get_iob() * get treatments from pumphistory once, not every time we get_iob() --- lib/determine-basal/cob-autosens.js | 8 +++++++- lib/iob/index.js | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/determine-basal/cob-autosens.js b/lib/determine-basal/cob-autosens.js index a06ee6224..8d05e9a65 100644 --- a/lib/determine-basal/cob-autosens.js +++ b/lib/determine-basal/cob-autosens.js @@ -1,5 +1,6 @@ var basal = require('oref0/lib/profile/basal'); var get_iob = require('oref0/lib/iob'); +var find_insulin = require('oref0/lib/iob/history'); var isf = require('../profile/isf'); function detectSensitivityandCarbAbsorption(inputs) { @@ -36,6 +37,9 @@ function detectSensitivityandCarbAbsorption(inputs) { } } + // get treatments from pumphistory once, not every time we get_iob() + var treatments = find_insulin(inputs.iob_inputs); + var avgDeltas = []; var bgis = []; var deviations = []; @@ -148,7 +152,9 @@ function detectSensitivityandCarbAbsorption(inputs) { iob_inputs.clock=bgTime; iob_inputs.profile.current_basal = basal.basalLookup(basalprofile, bgTime); //console.log(JSON.stringify(iob_inputs.profile)); - var iob = get_iob(iob_inputs, true)[0]; + //console.error("Before: ", new Date().getTime()); + var iob = get_iob(iob_inputs, true, treatments)[0]; + //console.error("After: ", new Date().getTime()); //console.log(JSON.stringify(iob)); var bgi = Math.round(( -iob.activity * sens * 5 )*100)/100; diff --git a/lib/iob/index.js b/lib/iob/index.js index ec1a89bdd..a58806f87 100644 --- a/lib/iob/index.js +++ b/lib/iob/index.js @@ -4,9 +4,11 @@ var find_insulin = require('./history'); var calculate = require('./calculate'); var sum = require('./total'); -function generate (inputs, currentIOBOnly) { +function generate (inputs, currentIOBOnly, treatments) { - var treatments = find_insulin(inputs); + if (!treatments) { + var treatments = find_insulin(inputs); + } var opts = { treatments: treatments From 88862cc24fc68e2254b2c5032c971d9e211f97ff Mon Sep 17 00:00:00 2001 From: AdrianLxM Date: Mon, 14 Aug 2017 01:31:41 +0200 Subject: [PATCH 023/215] remove double declaration of biobContrib (#605) --- lib/iob/calculate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/iob/calculate.js b/lib/iob/calculate.js index 1aed98cbd..307ae85e0 100644 --- a/lib/iob/calculate.js +++ b/lib/iob/calculate.js @@ -138,7 +138,7 @@ function iobCalc(treatment, time, dia, profile) { iobContrib = treatment.insulin * (1 - S * (1 - a) * ((Math.pow(t, 2) / (tau * td * (1 - a)) - t / tau - 1) * Math.exp(-t / tau) + 1)); // calculate bolus snooze insulin in the same pass t = t * profile.bolussnooze_dia_divisor; - var biobContrib = treatment.insulin * (1 - S * (1 - a) * ((Math.pow(t, 2) / (tau * td * (1 - a)) - t / tau - 1) * Math.exp(-t / tau) + 1)); + biobContrib = treatment.insulin * (1 - S * (1 - a) * ((Math.pow(t, 2) / (tau * td * (1 - a)) - t / tau - 1) * Math.exp(-t / tau) + 1)); //console.error('DIA: ' + dia + ' t: ' + t + ' td: ' + td + ' tp: ' + tp + ' tau: ' + tau + ' a: ' + a + ' S: ' + S + ' activityContrib: ' + activityContrib + ' iobContrib: ' + iobContrib); From 2319c2e5b9572298acdbf46a8cd222a4c5b6e1b6 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Aug 2017 21:07:46 -0700 Subject: [PATCH 024/215] first attempt at allowing unsuspend without SMB (#596) --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index e1f63dd20..bd5624d89 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -12,7 +12,7 @@ main() { && refresh_old_pumphistory_24h \ && refresh_old_profile \ && touch monitor/pump_loop_enacted -r monitor/glucose.json \ - && refresh_temp_and_enact \ + && ( refresh_temp_and_enact || ( smb_verify_status && refresh_temp_and_enact ) ) \ && refresh_pumphistory_and_enact \ && refresh_profile \ && refresh_pumphistory_24h \ From c4030a643edc7d51205c20ef92716996f5b5a8c1 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Aug 2017 21:08:41 -0700 Subject: [PATCH 025/215] Clean up old unused stuff, fix whitespace, etc. (#595) * remove unused refresh-loops.json * more unused-json cleanup * whitespace * remove old unused template stuff * remove duplicate if clause @AdrianLxM found --- bin/oref0-template.js | 27 - bin/oref0.sh | 15 - lib/determine-basal/determine-basal.js | 128 ++-- lib/oref0-setup/report.json | 10 +- lib/templates/exported-loop.json | 679 -------------------- lib/templates/index.js | 115 ---- lib/templates/medtronic-pump-reports.json | 233 ------- lib/templates/oref0-devices.json | 54 -- lib/templates/refresh-loops.json | 721 ---------------------- lib/templates/some-reports.json | 320 ---------- package.json | 1 - 11 files changed, 68 insertions(+), 2235 deletions(-) delete mode 100755 bin/oref0-template.js delete mode 100644 lib/templates/exported-loop.json delete mode 100644 lib/templates/index.js delete mode 100644 lib/templates/medtronic-pump-reports.json delete mode 100644 lib/templates/oref0-devices.json delete mode 100644 lib/templates/refresh-loops.json delete mode 100644 lib/templates/some-reports.json diff --git a/bin/oref0-template.js b/bin/oref0-template.js deleted file mode 100755 index eaefd01bf..000000000 --- a/bin/oref0-template.js +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env node - - - -var argv = require('yargs') - .usage("$0 [args]") - /* - .option('', { - }) - */ - .command('mint ', 'generate template for import', require('oref0/lib/templates/')) - // .choices('type', ['devices', 'reports', 'alias', '*']) - /* - .command('devices', 'generate common device loops', function (yargs) { - return yargs.option('b', { - alias: 'bar' - }); - }) - */ - .help('help') - .alias('h', 'help') - .completion( ) - .strict( ) - .argv - ; - -// console.log('after', argv); diff --git a/bin/oref0.sh b/bin/oref0.sh index 06938fc36..593f33525 100755 --- a/bin/oref0.sh +++ b/bin/oref0.sh @@ -20,9 +20,6 @@ $self Valid commands: oref0 device-helper - : create/template a device from bash commands easily oref0 alias-helper - : create/template a alias from bash commands easily - oref0 cron-5-minute-helper - - generate a cron template for commands - to run every 5 minutes: - oref0 cron-5-minute-helper openaps do-everything oref0 env - print information about environment. oref0 pebble oref0 ifttt-notify @@ -52,18 +49,6 @@ alias-helper) shift cat <&1 | logger -t openaps-loop - EOF ;; env) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 215e6f195..d9e1fb666 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -611,76 +611,74 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } } - if (eventualBG < min_bg) { - // if we've bolused recently, we can snooze until the bolus IOB decays (at double speed) - if (snoozeBG > min_bg) { // if adding back in the bolus contribution BG would be above min - // If we're not in SMB mode with COB, or lastCOBpredBG > target_bg, bolus snooze - if (! (microBolusAllowed && rT.COB) || lastCOBpredBG > target_bg) { - rT.reason += ", bolus snooze: eventual BG range " + convert_bg(eventualBG, profile) + "-" + convert_bg(snoozeBG, profile); - //console.error(currenttemp, basal ); - if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) { - rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. "; - return rT; - } else { - rT.reason += "; setting current basal of " + basal + " as temp. "; - return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); - } - } - } else { - // calculate 30m low-temp required to get projected BG up to target - // use snoozeBG to more gradually ramp in any counteraction of the user's boluses - // multiply by 2 to low-temp faster for increased hypo safety - var insulinReq = 2 * Math.min(0, (snoozeBG - target_bg) / sens); - insulinReq = round( insulinReq , 2); - // calculate naiveInsulinReq based on naive_eventualBG - var naiveInsulinReq = Math.min(0, (naive_eventualBG - target_bg) / sens); - naiveInsulinReq = round( naiveInsulinReq , 2); - if (minDelta < 0 && minDelta > expectedDelta) { - // if we're barely falling, newinsulinReq should be barely negative - rT.reason += ", Snooze BG " + convert_bg(snoozeBG, profile); - var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2); - //console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq); - insulinReq = newinsulinReq; - } - // rate required to deliver insulinReq less insulin over 30m: - var rate = basal + (2 * insulinReq); - rate = round_basal(rate, profile); - // if required temp < existing temp basal - var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60; - // if current temp would deliver a lot (30% of basal) less than the required insulin, - // by both normal and naive calculations, then raise the rate - var minInsulinReq = Math.min(insulinReq,naiveInsulinReq); - if (insulinScheduled < minInsulinReq - basal*0.3) { - rT.reason += ", "+currenttemp.duration + "m@" + (currenttemp.rate).toFixed(2) + " is a lot less than needed. "; - return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp); - } - if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 5 && rate >= currenttemp.rate * 0.8)) { - rT.reason += ", temp " + currenttemp.rate + " ~< req " + rate + "U/hr. "; + // if we've bolused recently, we can snooze until the bolus IOB decays (at double speed) + if (snoozeBG > min_bg) { // if adding back in the bolus contribution BG would be above min + // If we're not in SMB mode with COB, or lastCOBpredBG > target_bg, bolus snooze + if (! (microBolusAllowed && rT.COB) || lastCOBpredBG > target_bg) { + rT.reason += ", bolus snooze: eventual BG range " + convert_bg(eventualBG, profile) + "-" + convert_bg(snoozeBG, profile); + //console.error(currenttemp, basal ); + if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) { + rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. "; return rT; } else { - // calculate a long enough zero temp to eventually correct back up to target - if ( rate < 0 ) { - var bgUndershoot = target_bg - naive_eventualBG; - var worstCaseInsulinReq = bgUndershoot / sens; - var durationReq = round(60*worstCaseInsulinReq / profile.current_basal); - if (durationReq < 0) { - durationReq = 0; - // don't set a temp longer than 120 minutes - } else { - durationReq = round(durationReq/30)*30; - durationReq = Math.min(120,Math.max(0,durationReq)); - } - //console.error(durationReq); - //rT.reason += "insulinReq " + insulinReq + "; " - if (durationReq > 0) { - rT.reason += ", setting " + durationReq + "m zero temp. "; - return tempBasalFunctions.setTempBasal(rate, durationReq, profile, rT, currenttemp); - } + rT.reason += "; setting current basal of " + basal + " as temp. "; + return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + } + } + } else { + // calculate 30m low-temp required to get projected BG up to target + // use snoozeBG to more gradually ramp in any counteraction of the user's boluses + // multiply by 2 to low-temp faster for increased hypo safety + var insulinReq = 2 * Math.min(0, (snoozeBG - target_bg) / sens); + insulinReq = round( insulinReq , 2); + // calculate naiveInsulinReq based on naive_eventualBG + var naiveInsulinReq = Math.min(0, (naive_eventualBG - target_bg) / sens); + naiveInsulinReq = round( naiveInsulinReq , 2); + if (minDelta < 0 && minDelta > expectedDelta) { + // if we're barely falling, newinsulinReq should be barely negative + rT.reason += ", Snooze BG " + convert_bg(snoozeBG, profile); + var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2); + //console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq); + insulinReq = newinsulinReq; + } + // rate required to deliver insulinReq less insulin over 30m: + var rate = basal + (2 * insulinReq); + rate = round_basal(rate, profile); + // if required temp < existing temp basal + var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60; + // if current temp would deliver a lot (30% of basal) less than the required insulin, + // by both normal and naive calculations, then raise the rate + var minInsulinReq = Math.min(insulinReq,naiveInsulinReq); + if (insulinScheduled < minInsulinReq - basal*0.3) { + rT.reason += ", "+currenttemp.duration + "m@" + (currenttemp.rate).toFixed(2) + " is a lot less than needed. "; + return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp); + } + if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 5 && rate >= currenttemp.rate * 0.8)) { + rT.reason += ", temp " + currenttemp.rate + " ~< req " + rate + "U/hr. "; + return rT; + } else { + // calculate a long enough zero temp to eventually correct back up to target + if ( rate < 0 ) { + var bgUndershoot = target_bg - naive_eventualBG; + var worstCaseInsulinReq = bgUndershoot / sens; + var durationReq = round(60*worstCaseInsulinReq / profile.current_basal); + if (durationReq < 0) { + durationReq = 0; + // don't set a temp longer than 120 minutes } else { - rT.reason += ", setting " + rate + "U/hr. "; + durationReq = round(durationReq/30)*30; + durationReq = Math.min(120,Math.max(0,durationReq)); + } + //console.error(durationReq); + //rT.reason += "insulinReq " + insulinReq + "; " + if (durationReq > 0) { + rT.reason += ", setting " + durationReq + "m zero temp. "; + return tempBasalFunctions.setTempBasal(rate, durationReq, profile, rT, currenttemp); } - return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp); + } else { + rT.reason += ", setting " + rate + "U/hr. "; } + return tempBasalFunctions.setTempBasal(rate, 30, profile, rT, currenttemp); } } } diff --git a/lib/oref0-setup/report.json b/lib/oref0-setup/report.json index bc6573ffc..498a3cb23 100644 --- a/lib/oref0-setup/report.json +++ b/lib/oref0-setup/report.json @@ -382,12 +382,12 @@ { "type": "report", "name": "xdrip/glucose.json", - "xdrip/glucose.json": { - "device": "xdrip", - "remainder": "", - "use": "shell", + "xdrip/glucose.json": { + "device": "xdrip", + "remainder": "", + "use": "shell", "json_default": "True", - "reporter": "text" + "reporter": "text" } } ] diff --git a/lib/templates/exported-loop.json b/lib/templates/exported-loop.json deleted file mode 100644 index c7bc92b59..000000000 --- a/lib/templates/exported-loop.json +++ /dev/null @@ -1,679 +0,0 @@ -[ - { - "type": "alias", - "name": "rm-warmup", - "rm-warmup": { - "command": "! bash -c \"rm -f model.json monitor/clock.json > /dev/null\"" - } - }, - { - "type": "alias", - "name": "warmup", - "warmup": { - "command": "report invoke model.json raw-pump/clock-raw.json monitor/clock.json" - } - }, - { - "fail-warmup": { - "command": "! bash -c \"echo PREFLIGHT FAIL; exit 1\"" - }, - "type": "alias", - "name": "fail-warmup" - }, - { - "type": "alias", - "preflight": { - "command": "! bash -c \"(openaps rm-warmup; echo PREFLIGHT ) && openaps warmup 2>&1 >/dev/null && grep -q T monitor/clock.json && echo PREFLIGHT OK || openaps fail-warmup\"" - }, - "name": "preflight" - }, - { - "type": "alias", - "name": "monitor-cgm", - "monitor-cgm": { - "command": "report invoke monitor/glucose-raw.json monitor/glucose.json" - } - }, - { - "type": "alias", - "name": "monitor-pump-history", - "monitor-pump-history": { - "command": "report invoke raw-pump/pump-history-raw.json monitor/pump-history.json" - } - }, - { - "type": "alias", - "name": "get-basal-status", - "get-basal-status": { - "command": "report invoke monitor/temp-basal-status.json" - } - }, - { - "type": "alias", - "name": "get-pump-details", - "get-pump-details": { - "command": "report invoke monitor/reservoir.json monitor/status.json monitor/battery.json" - } - }, - { - "type": "alias", - "name": "get-settings", - "get-settings": { - "command": "report invoke raw-pump/bg-targets-raw.json settings/bg-targets.json raw-pump/insulin-sensitivities-raw.json settings/insulin-sensitivities.json raw-pump/selected-basal-profile.json settings/selected-basal-profile.json raw-pump/settings.json settings/settings.json" - } - }, - { - "type": "alias", - "name": "gather-pump-data", - "gather-pump-data": { - "command": "! bash -c \"openaps get-basal-status; openaps get-pump-details; openaps monitor-pump-history; openaps get-settings\"" - } - }, - { - "type": "alias", - "name": "gather-clean-data", - "gather-clean-data": { - "command": "! bash -c \"openaps monitor-cgm && openaps gather-pump-data\"" - } - }, - { - "type": "alias", - "name": "do-oref0", - "do-oref0": { - "command": "report invoke oref0-monitor/profile.json oref0-monitor/iob.json oref0-predict/oref0.json" - } - }, - { - "type": "alias", - "name": "enact-oref0", - "enact-oref0": { - "command": "report invoke oref0-enacted/enacted-temp-basal.json" - } - }, - { - "do-everything": { - "command": "! bash -c \"openaps preflight && openaps gather-clean-data && openaps do-oref0 && openaps enact-oref0\"" - }, - "type": "alias", - "name": "do-everything" - }, - { - "type": "vendor", - "name": "mmeowlink.vendors.mmeowlink", - "mmeowlink.vendors.mmeowlink": { - "path": ".", - "module": "mmeowlink.vendors.mmeowlink" - } - }, - { - "type": "vendor", - "name": "openxshareble", - "openxshareble": { - "path": ".", - "module": "openxshareble" - } - }, - { - "openapscontrib.timezones": { - "path": ".", - "module": "openapscontrib.timezones" - }, - "type": "vendor", - "name": "openapscontrib.timezones" - }, - { - "openapscontrib.mmhistorytools": { - "path": ".", - "module": "openapscontrib.mmhistorytools" - }, - "type": "vendor", - "name": "openapscontrib.mmhistorytools" - }, - { - "pancreabble": { - "path": ".", - "module": "pancreabble" - }, - "type": "vendor", - "name": "pancreabble" - }, - { - "main": { - "phases": "", - "rrule": "RRULE:FREQ=MINUTELY;INTERVAL=1" - }, - "type": "schedule", - "name": "main" - }, - { - "do-everything": { - "phases": "", - "rrule": "RRULE:FREQ=MINUTELY;INTERVAL=1" - }, - "type": "schedule", - "name": "do-everything" - }, - { - "pump": { - "vendor": "mmeowlink.vendors.mmeowlink", - "extra": "pump.ini" - }, - "type": "device", - "name": "pump", - "extra": { - "serial": "000000", - "radio_type": "subg_rfspy", - "port": "/dev/serial/by-id/usb-Nightscout_subg_rfspy_000002-if00" - } - }, - { - "extra": { - "fields": "", - "cmd": "oref0", - "args": "" - }, - "type": "device", - "name": "oref0", - "oref0": { - "vendor": "openaps.vendors.process", - "extra": "oref0.ini" - } - }, - { - "extra": { - "fields": "glucose pumphistory isf basal_profile profile", - "cmd": "oref0", - "args": "detect-sensitivity" - }, - "type": "device", - "name": "detect-sensitivity", - "detect-sensitivity": { - "vendor": "openaps.vendors.process", - "extra": "detect-sensitivity.ini" - } - }, - { - "extra": { - "fields": "settings bg-targets insulin-sensitivities basal-profile max-iob", - "cmd": "oref0", - "args": "get-profile" - }, - "type": "device", - "name": "get-profile", - "get-profile": { - "vendor": "openaps.vendors.process", - "extra": "get-profile.ini" - } - }, - { - "type": "device", - "calculate-iob": { - "vendor": "openaps.vendors.process", - "extra": "calculate-iob.ini" - }, - "name": "calculate-iob", - "extra": { - "fields": "pump-history oref0-profile clock", - "cmd": "oref0", - "args": "calculate-iob" - } - }, - { - "determine-basal": { - "vendor": "openaps.vendors.process", - "extra": "determine-basal.ini" - }, - "type": "device", - "name": "determine-basal", - "extra": { - "fields": "oref0-iob temp-basal glucose oref0-profile", - "cmd": "oref0", - "args": "determine-basal" - } - }, - { - "type": "device", - "tz": { - "vendor": "openapscontrib.timezones", - "extra": "tz.ini" - }, - "name": "tz", - "extra": {} - }, - { - "units": { - "vendor": "openaps.vendors.units", - "extra": "units.ini" - }, - "type": "device", - "name": "units", - "extra": {} - }, - { - "extra": {}, - "type": "device", - "name": "mmhistorytools", - "mmhistorytools": { - "vendor": "openapscontrib.mmhistorytools", - "extra": "mmhistorytools.ini" - } - }, - { - "type": "device", - "cgm": { - "vendor": "openxshareble", - "extra": "cgm.ini" - }, - "name": "cgm", - "extra": { - "serial": "SM12345678" - } - }, - { - "pong": { - "vendor": "openaps.vendors.process", - "extra": "pong.ini" - }, - "type": "device", - "name": "pong", - "extra": { - "fields": "thing", - "cmd": "echo", - "args": "" - } - }, - { - "ns": { - "vendor": "openaps.vendors.process", - "extra": "ns.ini" - }, - "type": "device", - "name": "ns", - "extra": { - "fields": "oper", - "cmd": "nightscout", - "args": "ns myhost.com 143505794bdd283f7daed50f42d201b6926892c8" - } - }, - { - "pebble": { - "vendor": "pancreabble", - "extra": "pebble.ini" - }, - "type": "device", - "name": "pebble", - "extra": {} - }, - { - "DoPing": { - "then": "" - }, - "type": "trigger", - "name": "DoPing" - }, - { - "type": "trigger", - "ping": { - "then": "pong" - }, - "name": "ping" - }, - { - "pong": { - "then": "" - }, - "type": "trigger", - "name": "pong" - }, - { - "settings/settings.json": { - "device": "pump", - "use": "read_settings", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/settings.json" - }, - { - "type": "report", - "name": "settings/bg-targets-raw.json", - "settings/bg-targets-raw.json": { - "device": "pump", - "use": "read_bg_targets", - "reporter": "JSON" - } - }, - { - "settings/bg-targets.json": { - "device": "units", - "to": "mg/dL", - "use": "bg_targets", - "input": "raw-pump/bg-targets-raw.json", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/bg-targets.json" - }, - { - "settings/insulin-sensitivities-raw.json": { - "device": "pump", - "use": "read_insulin_sensitivities", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/insulin-sensitivities-raw.json" - }, - { - "type": "report", - "name": "settings/insulin-sensitivities.json", - "settings/insulin-sensitivities.json": { - "device": "units", - "to": "mg/dL", - "use": "insulin_sensitivities", - "input": "raw-pump/insulin-sensitivities-raw.json", - "reporter": "JSON" - } - }, - { - "type": "report", - "name": "settings/selected-basal-profile.json", - "settings/selected-basal-profile.json": { - "device": "pump", - "use": "read_selected_basal_profile", - "reporter": "JSON" - } - }, - { - "monitor/clock-raw.json": { - "device": "pump", - "use": "read_clock", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/clock-raw.json" - }, - { - "monitor/clock.json": { - "use": "clock", - "reporter": "JSON", - "astimezone": "False", - "date": "None", - "adjust": "missing", - "timezone": "PST", - "device": "tz", - "input": "raw-pump/clock-raw.json" - }, - "type": "report", - "name": "monitor/clock.json" - }, - { - "monitor/temp-basal-status.json": { - "device": "pump", - "use": "read_temp_basal", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/temp-basal-status.json" - }, - { - "monitor/pump-history-raw.json": { - "hours": "8.0", - "device": "pump", - "use": "iter_pump_hours", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/pump-history-raw.json" - }, - { - "monitor/pump-history.json": { - "use": "rezone", - "reporter": "JSON", - "astimezone": "False", - "date": "timestamp dateString start_at end_at created_at", - "adjust": "missing", - "timezone": "PST", - "device": "tz", - "input": "raw-pump/pump-history-raw.json" - }, - "type": "report", - "name": "monitor/pump-history.json" - }, - { - "type": "report", - "name": "model.json", - "model.json": { - "device": "pump", - "use": "model", - "reporter": "JSON" - } - }, - { - "monitor/reservoir.json": { - "device": "pump", - "use": "reservoir", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/reservoir.json" - }, - { - "type": "report", - "name": "monitor/status.json", - "monitor/status.json": { - "device": "pump", - "use": "read_status", - "reporter": "JSON" - } - }, - { - "monitor/battery.json": { - "device": "pump", - "use": "read_battery_status", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/battery.json" - }, - { - "type": "report", - "name": "oref0-monitor/profile.json", - "oref0-monitor/profile.json": { - "insulin-sensitivities": "settings/insulin-sensitivities.json", - "use": "shell", - "settings": "settings/settings.json", - "reporter": "text", - "json_default": "True", - "device": "get-profile", - "bg-targets": "settings/bg-targets.json", - "basal-profile": "settings/selected-basal-profile.json", - "max-iob": "max-iob.json", - "remainder": "" - } - }, - { - "type": "report", - "name": "oref0-monitor/iob.json", - "oref0-monitor/iob.json": { - "use": "shell", - "clock": "monitor/clock.json", - "reporter": "text", - "json_default": "True", - "pump-history": "monitor/pump-history.json", - "oref0-profile": "oref0-monitor/profile.json", - "device": "calculate-iob", - "remainder": "" - } - }, - { - "type": "report", - "name": "oref0-predict/oref0.json", - "oref0-predict/oref0.json": { - "use": "shell", - "oref0-iob": "oref0-monitor/iob.json", - "temp-basal": "monitor/temp-basal-status.json", - "reporter": "text", - "json_default": "True", - "oref0-profile": "oref0-monitor/profile.json", - "device": "determine-basal", - "remainder": "", - "glucose": "monitor/glucose.json" - } - }, - { - "type": "report", - "name": "oref0-enacted/enacted-temp-basal.json", - "oref0-enacted/enacted-temp-basal.json": { - "device": "pump", - "input": "oref0-predict/oref0.json", - "use": "set_temp_basal", - "reporter": "JSON" - } - }, - { - "monitor/glucose-raw.json": { - "count": "20", - "device": "cgm", - "use": "iter_glucose", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/glucose-raw.json" - }, - { - "type": "report", - "name": "monitor/glucose.json", - "monitor/glucose.json": { - "use": "rezone", - "reporter": "JSON", - "astimezone": "False", - "date": "timestamp dateString start_at end_at created_at", - "adjust": "missing", - "timezone": "PST", - "device": "tz", - "input": "raw-cgm/glucose-raw.json" - } - }, - { - "cgm-vendor.json": { - "device": "cgm", - "use": "GetFirmwareHeader", - "reporter": "JSON" - }, - "type": "report", - "name": "cgm-vendor.json" - }, - { - "blah.txt": { - "thing": "foo", - "use": "shell", - "reporter": "text", - "device": "pong", - "remainder": "bar", - "json_default": "False" - }, - "type": "report", - "name": "blah.txt" - }, - { - "raw-pump/settings.json": { - "device": "pump", - "use": "read_settings", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/settings.json" - }, - { - "type": "report", - "name": "raw-pump/bg-targets-raw.json", - "raw-pump/bg-targets-raw.json": { - "device": "pump", - "use": "read_bg_targets", - "reporter": "JSON" - } - }, - { - "raw-pump/insulin-sensitivities-raw.json": { - "device": "pump", - "use": "read_insulin_sensitivities", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/insulin-sensitivities-raw.json" - }, - { - "type": "report", - "name": "raw-pump/selected-basal-profile.json", - "raw-pump/selected-basal-profile.json": { - "device": "pump", - "use": "read_selected_basal_profile", - "reporter": "JSON" - } - }, - { - "raw-pump/clock-raw.json": { - "device": "pump", - "use": "read_clock", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/clock-raw.json" - }, - { - "raw-pump/temp-basal-status.json": { - "device": "pump", - "use": "read_temp_basal", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/temp-basal-status.json" - }, - { - "raw-pump/pump-history-raw.json": { - "hours": "8.0", - "device": "pump", - "use": "iter_pump_hours", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/pump-history-raw.json" - }, - { - "raw-pump/reservoir.json": { - "device": "pump", - "use": "reservoir", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/reservoir.json" - }, - { - "type": "report", - "name": "raw-pump/status.json", - "raw-pump/status.json": { - "device": "pump", - "use": "read_status", - "reporter": "JSON" - } - }, - { - "raw-pump/battery.json": { - "device": "pump", - "use": "read_battery_status", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/battery.json" - }, - { - "type": "report", - "name": "raw-cgm/glucose-raw.json", - "raw-cgm/glucose-raw.json": { - "count": "20", - "device": "cgm", - "use": "iter_glucose", - "reporter": "JSON" - } - } -] diff --git a/lib/templates/index.js b/lib/templates/index.js deleted file mode 100644 index 16009ad65..000000000 --- a/lib/templates/index.js +++ /dev/null @@ -1,115 +0,0 @@ - - -exports.xyzbuilder = { - foo: { - default: 'ok' - }, - baz: { - default: 'optional' - } - -}; - -var reference = require('./exported-loop.json'); - - -function oref0_reports (argv) { - var reference = require('./some-reports'); - var devs = [ ]; - if (argv.oref0) { - reference.forEach(function (item) { - if (item.type == 'report') { - // if (item[item.name].device == 'pump') { - if ([null, 'get-profile', 'calculate-iob', 'determine-basal'].indexOf(item[item.name].device) > 0) { - devs.push(item); - } - } - }); - - } - console.log(JSON.stringify(devs, ' ')); -} - -function oref0_devices (argv) { - var devs = [ ]; - if (argv.oref0) { - reference.forEach(function (item) { - if (item.type == 'device') { - if (item.extra.cmd == 'oref0') { - devs.push(item); - } - } - }); - - } - console.log(JSON.stringify(devs, ' ')); -} - -function per_type (yargs) { - return yargs - .command('oref0', 'generate oref0 devices', {oref0: {default: true}}, oref0_devices) - ; -} - -function per_shape (yargs) { - return yargs - .command('oref0-inputs', 'generate reports for oref0', {oref0: {default: true}}, oref0_reports) - .command('medtronic-pump', 'organize output from medtronic pump', {name: {default: 'pump'}}, medtronic_pump_reports) - // .command('glucose', '', { }, oref0_reports) - ; -} - -function medtronic_pump_reports (argv) { - var reference = require('./medtronic-pump-reports'); - var out = [ ]; - reference.forEach(function (item) { - if (item[item.name].device == 'pump') { - if (argv.name != 'pump') { - item[item.name].device = argv.name; - } - } - out.push(item); - }); - console.log(JSON.stringify(out)); - return out; -} - -function per_alias (yargs) { - return yargs - .command('common', 'generate common aliases', {common: {default: true}}, print_aliases) -} - -function print_aliases (argv) { - var devs = [ ]; - if (argv.common) { - reference.forEach(function (item) { - if (item.type == 'alias') { - devs.push(item); - } - }); - } - console.log(JSON.stringify(devs, ' ')); -} - - -function run ( ) { -} - -exports.builder = function (yargs) { - return yargs - .command('device ', 'generate devices', per_type, run) - .command('reports ', 'generate reports', per_shape, run) - .command('alias ', 'generate aliases', per_alias, run) - .strict( ) - // .usage('$0 mint ') - // .demand('type', 1) - // .choices('type', ['devices', 'reports', 'alias', '*']) - // .options('bazbaz', { default: 'blah' }) - ; -} - -exports.handler = function (argv) { - // console.log('args', argv); - // return argv.command( - -} diff --git a/lib/templates/medtronic-pump-reports.json b/lib/templates/medtronic-pump-reports.json deleted file mode 100644 index f232030ee..000000000 --- a/lib/templates/medtronic-pump-reports.json +++ /dev/null @@ -1,233 +0,0 @@ -[ - { - "type": "report", - "name": "raw-pump/bg-targets-raw.json", - "raw-pump/bg-targets-raw.json": { - "device": "pump", - "use": "read_bg_targets", - "reporter": "JSON" - } - }, - { - "settings/bg-targets.json": { - "device": "units", - "to": "mg/dL", - "use": "bg_targets", - "input": "raw-pump/bg-targets-raw.json", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/bg-targets.json" - }, - { - "raw-pump/insulin-sensitivities-raw.json": { - "device": "pump", - "use": "read_insulin_sensitivities", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/insulin-sensitivities-raw.json" - }, - { - "type": "report", - "name": "settings/insulin-sensitivities.json", - "settings/insulin-sensitivities.json": { - "device": "units", - "to": "mg/dL", - "use": "insulin_sensitivities", - "input": "raw-pump/insulin-sensitivities-raw.json", - "reporter": "JSON" - } - }, - { - "raw-pump/clock-raw.json": { - "device": "pump", - "use": "read_clock", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/clock-raw.json" - }, - { - "monitor/clock.json": { - "use": "clock", - "reporter": "JSON", - "astimezone": "False", - "date": "None", - "adjust": "missing", - "device": "tz", - "input": "raw-pump/clock-raw.json" - }, - "type": "report", - "name": "monitor/clock.json" - }, - { - "monitor/temp-basal-status.json": { - "device": "pump", - "use": "read_temp_basal", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/temp-basal-status.json" - }, - { - "type": "report", - "name": "oref0-predict/oref0.json", - "oref0-predict/oref0.json": { - "use": "shell", - "oref0-iob": "oref0-monitor/iob.json", - "temp-basal": "monitor/temp-basal-status.json", - "reporter": "text", - "json_default": "True", - "oref0-profile": "oref0-monitor/profile.json", - "device": "determine-basal", - "remainder": "", - "glucose": "monitor/glucose.json" - } - }, - { - "raw-pump/pump-history-raw.json": { - "hours": "8.0", - "device": "pump", - "use": "iter_pump_hours", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/pump-history-raw.json" - }, - { - "monitor/pump-history.json": { - "use": "rezone", - "reporter": "JSON", - "astimezone": "False", - "date": "timestamp dateString start_at end_at created_at", - "adjust": "missing", - "device": "tz", - "input": "raw-pump/pump-history-raw.json" - }, - "type": "report", - "name": "monitor/pump-history.json" - }, - { - "type": "report", - "name": "model.json", - "model.json": { - "device": "pump", - "use": "model", - "reporter": "JSON" - } - }, - { - "monitor/reservoir.json": { - "device": "pump", - "use": "reservoir", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/reservoir.json" - }, - { - "type": "report", - "name": "monitor/status.json", - "monitor/status.json": { - "device": "pump", - "use": "read_status", - "reporter": "JSON" - } - }, - { - "monitor/battery.json": { - "device": "pump", - "use": "read_battery_status", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/battery.json" - }, - { - "type": "report", - "name": "oref0-enacted/enacted-temp-basal.json", - "oref0-enacted/enacted-temp-basal.json": { - "device": "pump", - "input": "oref0-predict/oref0.json", - "use": "set_temp_basal", - "reporter": "JSON" - } - }, - { - "settings/settings.json": { - "device": "oref0", - "remainder": "copy-fresher raw-pump/settings.json", - "use": "shell", - "json_default": "True", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/settings.json" - }, - { - "raw-pump/settings.json": { - "device": "pump", - "use": "read_settings", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/settings.json" - }, - { - "type": "report", - "name": "settings/selected-basal-profile.json", - "settings/selected-basal-profile.json": { - "device": "oref0", - "remainder": "copy-fresher raw-pump/selected-basal-profile.json", - "use": "shell", - "json_default": "True", - "reporter": "JSON" - } - }, - { - "type": "report", - "name": "raw-pump/selected-basal-profile.json", - "raw-pump/selected-basal-profile.json": { - "device": "pump", - "use": "read_selected_basal_profile", - "reporter": "JSON" - } - }, - { - "raw-pump/temp-basal-status.json": { - "device": "pump", - "use": "read_temp_basal", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/temp-basal-status.json" - }, - { - "raw-pump/reservoir.json": { - "device": "pump", - "use": "reservoir", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/reservoir.json" - }, - { - "type": "report", - "name": "raw-pump/status.json", - "raw-pump/status.json": { - "device": "pump", - "use": "read_status", - "reporter": "JSON" - } - }, - { - "raw-pump/battery.json": { - "device": "pump", - "use": "read_battery_status", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/battery.json" - } -] diff --git a/lib/templates/oref0-devices.json b/lib/templates/oref0-devices.json deleted file mode 100644 index ec63d730d..000000000 --- a/lib/templates/oref0-devices.json +++ /dev/null @@ -1,54 +0,0 @@ -[ - { - "extra": { - "fields": "", - "cmd": "oref0", - "args": "" - }, - "type": "device", - "name": "oref0", - "oref0": { - "vendor": "openaps.vendors.process", - "extra": "oref0.ini" - } - }, - { - "extra": { - "fields": "settings bg-targets insulin-sensitivities basal-profile max-iob", - "cmd": "oref0", - "args": "get-profile" - }, - "type": "device", - "name": "get-profile", - "get-profile": { - "vendor": "openaps.vendors.process", - "extra": "get-profile.ini" - } - }, - { - "type": "device", - "calculate-iob": { - "vendor": "openaps.vendors.process", - "extra": "calculate-iob.ini" - }, - "name": "calculate-iob", - "extra": { - "fields": "pump-history oref0-profile clock", - "cmd": "oref0", - "args": "calculate-iob" - } - }, - { - "determine-basal": { - "vendor": "openaps.vendors.process", - "extra": "determine-basal.ini" - }, - "type": "device", - "name": "determine-basal", - "extra": { - "fields": "oref0-iob temp-basal glucose oref0-profile", - "cmd": "oref0", - "args": "determine-basal" - } - } -] diff --git a/lib/templates/refresh-loops.json b/lib/templates/refresh-loops.json deleted file mode 100644 index f9d0eb8a7..000000000 --- a/lib/templates/refresh-loops.json +++ /dev/null @@ -1,721 +0,0 @@ -[ - { - "openapscontrib.timezones": { - "path": ".", - "module": "openapscontrib.timezones" - }, - "type": "vendor", - "name": "openapscontrib.timezones" - }, - { - "type": "vendor", - "name": "mmeowlink.vendors.mmeowlink", - "mmeowlink.vendors.mmeowlink": { - "path": ".", - "module": "mmeowlink.vendors.mmeowlink" - } - }, - { - "type": "report", - "name": "monitor/cgm-glucose.json", - "monitor/cgm-glucose.json": { - "hours": "25.0", - "device": "cgm", - "use": "iter_glucose_hours", - "reporter": "JSON" - } - }, - { - "type": "report", - "name": "raw-cgm/raw-entries.json", - "raw-cgm/raw-entries.json": { - "count": "", - "use": "oref0_glucose", - "no_raw": "False", - "reporter": "JSON", - "seconds": "", - "minutes": "", - "hours": "25", - "device": "cgm", - "gaps": "", - "microseconds": "", - "threshold": "100", - "sensor": "", - "date": "display_time", - "glucose": "" - } - }, - { - "cgm/ns-glucose.json": { - "device": "ns-glucose", - "remainder": "", - "use": "shell", - "json_default": "True", - "reporter": "text" - }, - "type": "report", - "name": "cgm/ns-glucose.json" - }, - { - "type": "report", - "monitor/mmtune.json": { - "device": "pump", - "use": "mmtune", - "reporter": "JSON" - }, - "name": "monitor/mmtune.json" - }, - { - "type": "report", - "settings/model.json": { - "device": "pump", - "use": "model", - "reporter": "JSON" - }, - "name": "settings/model.json" - }, - { - "monitor/clock.json": { - "device": "pump", - "use": "read_clock", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/clock.json" - }, - { - "type": "report", - "name": "cgm/cgm-glucose.json", - "cgm/cgm-glucose.json": { - "use": "rezone", - "reporter": "JSON", - "astimezone": "False", - "date": "display_time dateString", - "adjust": "missing", - "input": "raw-cgm/raw-entries.json", - "device": "tz", - "timezone": "" - } - }, - { - "monitor/clock-zoned.json": { - "use": "clock", - "reporter": "JSON", - "astimezone": "False", - "date": "None", - "adjust": "missing", - "input": "monitor/clock.json", - "device": "tz", - "timezone": "" - }, - "type": "report", - "name": "monitor/clock-zoned.json" - }, - { - "type": "report", - "name": "monitor/temp_basal.json", - "monitor/temp_basal.json": { - "device": "pump", - "use": "read_temp_basal", - "reporter": "JSON" - } - }, - { - "monitor/reservoir.json": { - "device": "pump", - "use": "reservoir", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/reservoir.json" - }, - { - "monitor/battery.json": { - "device": "pump", - "use": "read_battery_status", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/battery.json" - }, - { - "type": "report", - "name": "monitor/status.json", - "monitor/status.json": { - "device": "pump", - "use": "status", - "reporter": "JSON" - } - }, - { - "type": "report", - "name": "monitor/pumphistory.json", - "monitor/pumphistory.json": { - "hours": "5.0", - "device": "pump", - "use": "iter_pump_hours", - "reporter": "JSON" - } - }, - { - "settings/pumphistory-24h.json": { - "hours": "27.0", - "device": "pump", - "use": "iter_pump_hours", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/pumphistory-24h.json" - }, - { - "monitor/pumphistory-zoned.json": { - "use": "rezone", - "reporter": "JSON", - "astimezone": "False", - "date": "timestamp dateString start_at end_at created_at", - "adjust": "missing", - "input": "monitor/pumphistory.json", - "device": "tz", - "timezone": "" - }, - "type": "report", - "name": "monitor/pumphistory-zoned.json" - }, - { - "type": "report", - "name": "settings/pumphistory-24h-zoned.json", - "settings/pumphistory-24h-zoned.json": { - "use": "rezone", - "reporter": "JSON", - "astimezone": "False", - "date": "timestamp dateString start_at end_at created_at", - "adjust": "missing", - "input": "settings/pumphistory-24h.json", - "device": "tz", - "timezone": "" - } - }, - { - "type": "report", - "name": "monitor/iob.json", - "monitor/iob.json": { - "profile": "settings/profile.json", - "use": "shell", - "clock": "monitor/clock-zoned.json", - "reporter": "text", - "json_default": "True", - "pumphistory": "monitor/pumphistory-zoned.json", - "device": "iob", - "remainder": "" - } - }, - { - "type": "report", - "name": "monitor/meal.json", - "monitor/meal.json": { - "profile": "settings/profile.json", - "carbs": "monitor/glucose.json", - "clock": "monitor/clock-zoned.json", - "reporter": "text", - "json_default": "True", - "use": "shell", - "pumphistory": "monitor/pumphistory-zoned.json", - "basal": "monitor/carbhistory.json", - "device": "meal", - "remainder": "", - "glucose": "settings/basal_profile.json" - } - }, - { - "type": "report", - "settings/autosens.json": { - "profile": "settings/profile.json", - "use": "shell", - "reporter": "text", - "basal_profile": "settings/basal_profile.json", - "json_default": "True", - "pumphistory": "settings/pumphistory-24h-zoned.json", - "device": "detect-sensitivity", - "remainder": "", - "isf": "settings/insulin_sensitivities.json", - "glucose": "monitor/glucose.json" - }, - "name": "settings/autosens.json" - }, - { - "type": "report", - "settings/bg_targets.json": { - "device": "pump", - "use": "read_bg_targets", - "reporter": "JSON" - }, - "name": "settings/bg_targets.json" - }, - { - "settings/insulin_sensitivities.json": { - "device": "pump", - "use": "read_insulin_sensitivities", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/insulin_sensitivities.json" - }, - { - "settings/carb_ratios.json": { - "device": "pump", - "use": "read_carb_ratios", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/carb_ratios.json" - }, - { - "settings/basal_profile.json": { - "device": "pump", - "use": "read_selected_basal_profile", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/basal_profile.json" - }, - { - "settings/settings.json": { - "device": "pump", - "use": "read_settings", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/settings.json" - }, - { - "settings/profile.json": { - "use": "shell", - "bg_targets": "settings/bg_targets.json", - "preferences": "preferences.json", - "settings": "settings/settings.json", - "basal_profile": "settings/basal_profile.json", - "reporter": "text", - "json_default": "True", - "carb_ratios": "settings/carb_ratios.json", - "device": "get-profile", - "remainder": "settings/temptargets.json", - "isf": "settings/insulin_sensitivities.json" - }, - "type": "report", - "name": "settings/profile.json" - }, - { - "type": "report", - "name": "enact/suggested.json", - "enact/suggested.json": { - "profile": "settings/profile.json", - "use": "shell", - "temp_basal": "monitor/temp_basal.json", - "reporter": "text", - "json_default": "True", - "meal": "monitor/meal.json", - "autosens": "settings/autosens.json", - "device": "determine-basal", - "remainder": "", - "iob": "monitor/iob.json", - "glucose": "monitor/glucose.json" - } - }, - { - "type": "report", - "enact/enacted.json": { - "device": "pump", - "input": "enact/suggested.json", - "use": "set_temp_basal", - "reporter": "JSON" - }, - "name": "enact/enacted.json" - }, - { - "type": "report", - "upload/pebble.json": { - "suggested": "enact/suggested.json", - "use": "shell", - "temp_basal": "monitor/temp_basal.json", - "reporter": "text", - "basal_profile": "settings/basal_profile.json", - "json_default": "True", - "meal": "monitor/meal.json", - "device": "pebble", - "enacted": "enact/enacted.json", - "remainder": "", - "iob": "monitor/iob.json", - "glucose": "monitor/glucose.json" - }, - "name": "upload/pebble.json" - }, - { - "type": "device", - "cgm": { - "vendor": "openaps.vendors.dexcom", - "extra": "cgm.ini" - }, - "name": "cgm", - "extra": {} - }, - { - "ns-glucose": { - "vendor": "openaps.vendors.process", - "extra": "ns-glucose.ini" - }, - "type": "device", - "name": "ns-glucose", - "extra": { - "fields": "", - "cmd": "bash -c \"curl --compressed -m 30 -s $NIGHTSCOUT_HOST/api/v1/entries/sgv.json?count=1000 | json -e \\\"this.glucose = this.sgv\\\"\"", - "args": "" - } - }, - { - "extra": { - "fields": "", - "cmd": "oref0", - "args": "" - }, - "type": "device", - "name": "oref0", - "oref0": { - "vendor": "openaps.vendors.process", - "extra": "oref0.ini" - } - }, - { - "extra": { - "fields": "pumphistory profile clock", - "cmd": "oref0", - "args": "calculate-iob" - }, - "type": "device", - "name": "iob", - "iob": { - "vendor": "openaps.vendors.process", - "extra": "iob.ini" - } - }, - { - "extra": { - "fields": "pumphistory profile clock carbs glucose basal", - "cmd": "oref0", - "args": "meal" - }, - "type": "device", - "name": "meal", - "meal": { - "vendor": "openaps.vendors.process", - "extra": "meal.ini" - } - }, - { - "extra": { - "fields": "settings bg_targets isf basal_profile preferences carb_ratios", - "cmd": "oref0", - "args": "get-profile" - }, - "type": "device", - "name": "get-profile", - "get-profile": { - "vendor": "openaps.vendors.process", - "extra": "get-profile.ini" - } - }, - { - "extra": { - "fields": "glucose pumphistory isf basal_profile profile", - "cmd": "oref0", - "args": "detect-sensitivity" - }, - "type": "device", - "name": "detect-sensitivity", - "detect-sensitivity": { - "vendor": "openaps.vendors.process", - "extra": "detect-sensitivity.ini" - } - }, - { - "determine-basal": { - "vendor": "openaps.vendors.process", - "extra": "determine-basal.ini" - }, - "type": "device", - "name": "determine-basal", - "extra": { - "fields": "iob temp_basal glucose profile autosens meal", - "cmd": "oref0", - "args": "determine-basal" - } - }, - { - "pebble": { - "vendor": "openaps.vendors.process", - "extra": "pebble.ini" - }, - "type": "device", - "name": "pebble", - "extra": { - "fields": "glucose iob basal_profile temp_basal suggested enacted meal", - "cmd": "oref0", - "args": "pebble" - } - }, - { - "type": "device", - "tz": { - "vendor": "openapscontrib.timezones", - "extra": "tz.ini" - }, - "name": "tz", - "extra": {} - }, - { - "openapscontrib.timezones": { - "path": ".", - "module": "openapscontrib.timezones" - }, - "type": "vendor", - "name": "openapscontrib.timezones" - }, - { - "type": "vendor", - "name": "mmeowlink.vendors.mmeowlink", - "mmeowlink.vendors.mmeowlink": { - "path": ".", - "module": "mmeowlink.vendors.mmeowlink" - } - }, - { - "type": "alias", - "name": "invoke", - "invoke": { - "command": "report invoke" - } - }, - { - "type": "alias", - "name": "mmtune", - "mmtune": { - "command": "! bash -c \"echo -n \\\"mmtune: \\\" && openaps report invoke monitor/mmtune.json 2>/dev/null >/dev/null; grep -v setFreq monitor/mmtune.json | grep -A2 $(json -a setFreq -f monitor/mmtune.json) | while read line; do echo -n \\\"$line \\\"; done\"" - } - }, - { - "type": "alias", - "name": "wait-for-silence", - "wait-for-silence": { - "command": "! bash -c \"echo -n \\\"Listening: \\\"; for i in $(seq 1 100); do echo -n .; ~/src/mmeowlink/bin/mmeowlink-any-pump-comms.py --port /dev/mmeowlink --wait-for 30 2>/dev/null | egrep -v subg | egrep No && break; done\"" - } - }, - { - "wait-for-long-silence": { - "command": "! bash -c \"echo -n \\\"Listening: \\\"; for i in $(seq 1 100); do echo -n .; ~/src/mmeowlink/bin/mmeowlink-any-pump-comms.py --port /dev/mmeowlink --wait-for 45 2>/dev/null | egrep -v subg | egrep No && break; done\"" - }, - "type": "alias", - "name": "wait-for-long-silence" - }, - { - "type": "alias", - "name": "monitor-cgm", - "monitor-cgm": { - "command": "report invoke raw-cgm/raw-entries.json cgm/cgm-glucose.json" - } - }, - { - "type": "alias", - "name": "get-ns-glucose", - "get-ns-glucose": { - "command": "report invoke cgm/ns-glucose.json" - } - }, - { - "monitor-pump": { - "command": "report invoke monitor/clock.json monitor/temp_basal.json monitor/pumphistory.json monitor/pumphistory-zoned.json monitor/clock-zoned.json monitor/iob.json monitor/meal.json monitor/reservoir.json monitor/battery.json monitor/status.json" - }, - "type": "alias", - "name": "monitor-pump" - }, - { - "type": "alias", - "ns-temptargets": { - "command": "! bash -c \"curl --compressed -m 30 -s \\\"$NIGHTSCOUT_HOST/api/v1/treatments.json?find\\[created_at\\]\\[\\$gte\\]=$(date -d \\\"6 hours ago\\\" -Iminutes)&find\\[eventType\\]\\[\\$regex\\]=Target\\\" > settings/temptargets.json; openaps report invoke settings/profile.json 2>/dev/null >/dev/null; exit 0 \"" - }, - "name": "ns-temptargets" - }, - { - "ns-meal-carbs": { - "command": "! bash -c \"curl --compressed -m 30 -s \\\"$NIGHTSCOUT_HOST/api/v1/treatments.json?find\\[carbs\\]\\[\\$exists\\]=true\\\" > monitor/carbhistory.json; oref0-meal monitor/pumphistory-zoned.json settings/profile.json monitor/clock-zoned.json monitor/carbhistory.json monitor/glucose.json settings/basal_profile.json > monitor/meal.json.new; grep -q COB monitor/meal.json.new && mv monitor/meal.json.new monitor/meal.json; exit 0\"" - }, - "type": "alias", - "name": "ns-meal-carbs" - }, - { - "type": "alias", - "name": "get-settings", - "get-settings": { - "command": "report invoke settings/model.json settings/bg_targets.json settings/insulin_sensitivities.json settings/basal_profile.json settings/settings.json settings/carb_ratios.json settings/profile.json" - } - }, - { - "type": "alias", - "name": "bg-fresh-check", - "bg-fresh-check": { - "command": "! bash -c \"cat cgm/glucose.json | json -c \\\"minAgo=(new Date()-new Date(this.dateString))/60/1000; return minAgo < 6 && minAgo > 0 && this.glucose > 38\\\" | grep -q glucose\"" - } - }, - { - "get-bg": { - "command": "! bash -c \"openaps monitor-cgm 2>/dev/null | tail -1 && grep -q glucose cgm/cgm-glucose.json && cp -pu cgm/cgm-glucose.json cgm/glucose.json; cp -pu cgm/glucose.json monitor/glucose.json\"" - }, - "type": "alias", - "name": "get-bg" - }, - { - "type": "alias", - "name": "get-ns-bg", - "get-ns-bg": { - "command": "! bash -c \"openaps get-ns-glucose && cat cgm/ns-glucose.json | json -c \\\"minAgo=(new Date()-new Date(this.dateString))/60/1000; return minAgo < 10 && minAgo > -5 && this.glucose > 38\\\" | grep -q glucose && cp -pu cgm/ns-glucose.json cgm/glucose.json; cp -pu cgm/glucose.json monitor/glucose.json\"" - } - }, - { - "gather": { - "command": "! bash -c \"openaps report invoke monitor/status.json 2>/dev/null >/dev/null && echo -n Ref && test $(cat monitor/status.json | json bolusing) == false && echo -n resh && ( openaps monitor-pump || openaps monitor-pump ) 2>/dev/null >/dev/null && echo ed pumphistory || (echo; exit 1) 2>/dev/null\"" - }, - "type": "alias", - "name": "gather" - }, - { - "type": "alias", - "autosens": { - "command": "! bash -c \"(find settings/ -newer settings/autosens.json | grep -q pumphistory-24h-zoned.json || find settings/ -size -5c | grep -q autosens.json || ! find settings/ | grep -q autosens || ! find settings/autosens.json) && openaps invoke settings/autosens.json\"" - }, - "name": "autosens" - }, - { - "type": "alias", - "name": "refresh-old-pumphistory", - "refresh-old-pumphistory": { - "command": "! bash -c \"find monitor/ -mmin -15 -size +100c | grep -q pumphistory-zoned || ( echo -n \\\"Old pumphistory: \\\" && openaps gather && openaps enact ) \"" - } - }, - { - "refresh-old-pumphistory-24h": { - "command": "! bash -c \"find settings/ -mmin -120 -size +100c | grep -q pumphistory-24h-zoned || (echo -n Old pumphistory-24h refresh && openaps report invoke settings/pumphistory-24h.json settings/pumphistory-24h-zoned.json 2>/dev/null >/dev/null && echo ed)\"" - }, - "type": "alias", - "name": "refresh-old-pumphistory-24h" - }, - { - "refresh-temp-and-enact": { - "command": "! bash -c \"if( (find monitor/ -newer monitor/temp_basal.json | grep -q glucose.json && echo glucose.json newer than temp_basal.json ) || (! find monitor/ -mmin -5 -size +5c | grep -q temp_basal && echo temp_basal.json more than 5m old)); then (echo -n Temp refresh && openaps report invoke monitor/temp_basal.json monitor/clock.json monitor/clock-zoned.json monitor/iob.json 2>/dev/null >/dev/null && echo ed && if(cat monitor/temp_basal.json | json -c \\\"this.duration < 27\\\" | grep -q duration); then openaps enact; else echo Temp duration 27m or more; fi); else echo temp_basal.json less than 5m old; fi\"" - }, - "type": "alias", - "name": "refresh-temp-and-enact" - }, - { - "type": "alias", - "name": "refresh-pumphistory-and-enact", - "refresh-pumphistory-and-enact": { - "command": "! bash -c \"if ((find monitor/ -newer monitor/pumphistory-zoned.json | grep -q glucose.json && echo -n glucose.json newer than pumphistory) || (find enact/ -newer monitor/pumphistory-zoned.json | grep -q enacted.json && echo -n enacted.json newer than pumphistory) || (! find monitor/ -mmin -5 | grep -q pumphistory-zoned && echo -n pumphistory more than 5m old) ); then (echo -n \\\": \\\" && openaps gather && openaps enact ); else echo Pumphistory less than 5m old; fi \"" - } - }, - { - "refresh-old-profile": { - "command": "! bash -c \"find settings/ -mmin -60 -size +5c | grep -q settings/profile.json && echo Profile less than 60m old || (echo -n Old settings refresh && openaps get-settings 2>/dev/null >/dev/null && echo ed )\"" - }, - "type": "alias", - "name": "refresh-old-profile" - }, - { - "refresh-profile": { - "command": "! bash -c \"find settings/ -mmin -10 -size +5c | grep -q settings.json && echo Settings less than 10m old || (echo -n Settings refresh && openaps get-settings 2>/dev/null >/dev/null && echo ed)\"" - }, - "type": "alias", - "name": "refresh-profile" - }, - { - "refresh-pumphistory-24h": { - "command": "! bash -c \"find settings/ -mmin -20 -size +100c | grep -q pumphistory-24h-zoned && echo Pumphistory-24 less than 20m old || (echo -n pumphistory-24h refresh && openaps report invoke settings/pumphistory-24h.json settings/pumphistory-24h-zoned.json 2>/dev/null >/dev/null && echo ed)\"" - }, - "type": "alias", - "name": "refresh-pumphistory-24h" - }, - { - "merge-pumphistory-long": { - "command": "! bash -c \"jq -s \\\".[0] + .[1]|unique|sort_by(.timestamp)|reverse\\\" settings/pumphistory-long.json monitor/pumphistory-zoned.json settings/pumphistory-24h-zoned.json > pumphistory-long.json.new && mv pumphistory-long.json.new settings/pumphistory-long.json\"" - }, - "type": "alias", - "name": "merge-pumphistory-long" - }, - { - "type": "alias", - "name": "enact", - "enact": { - "command": "! bash -c \"rm enact/suggested.json; openaps invoke enact/suggested.json && if (cat enact/suggested.json | json -0 && grep -q duration enact/suggested.json); then ( rm enact/enacted.json; openaps invoke enact/enacted.json ; grep -q duration enact/enacted.json || openaps invoke enact/enacted.json ) 2>&1 | egrep -v \\\"^ |subg_rfspy|handler\\\" ; grep incorrectly enact/suggested.json && ~/src/oref0/bin/clockset.sh 2>/dev/null; cat enact/enacted.json | json -0; fi\"" - } - }, - { - "type": "alias", - "name": "ns-loop", - "ns-loop": { - "command": "! bash -c \"echo Starting ns-loop at $(date): && openaps get-ns-bg; openaps autosens; openaps ns-temptargets && echo -n Refreshed temptargets && openaps ns-meal-carbs && echo \\\" and meal-carbs\\\" && openaps upload\"" - } - }, - { - "pump-loop": { - "command": "! bash -c \"sleep $[ ( $RANDOM / 2048 ) ]s; until(echo Starting pump-loop at $(date): && openaps wait-for-silence && openaps refresh-old-pumphistory && openaps refresh-old-pumphistory-24h && openaps refresh-old-profile && openaps refresh-temp-and-enact && openaps refresh-pumphistory-and-enact && openaps refresh-profile && openaps refresh-pumphistory-24h && echo Completed pump-loop at $(date) && echo); do echo Error, retrying && [[ $RANDOM > 30000 ]] && openaps wait-for-long-silence && openaps mmtune; sleep 5; done\"" - }, - "type": "alias", - "name": "pump-loop" - }, - { - "pebble": { - "command": "! bash -c \"grep -q iob monitor/iob.json && grep -q absolute enact/suggested.json && openaps report invoke upload/pebble.json\"" - }, - "type": "alias", - "name": "pebble" - }, - { - "type": "alias", - "name": "latest-ns-treatment-time", - "latest-ns-treatment-time": { - "command": "! bash -c \"nightscout latest-openaps-treatment $NIGHTSCOUT_HOST | json created_at\"" - } - }, - { - "type": "alias", - "name": "format-latest-nightscout-treatments", - "format-latest-nightscout-treatments": { - "command": "! bash -c \"nightscout cull-latest-openaps-treatments monitor/pumphistory-zoned.json settings/model.json $(openaps latest-ns-treatment-time) > upload/latest-treatments.json\"" - } - }, - { - "type": "alias", - "name": "upload-recent-treatments", - "upload-recent-treatments": { - "command": "! bash -c \"openaps format-latest-nightscout-treatments && test $(json -f upload/latest-treatments.json -a created_at eventType | wc -l ) -gt 0 && (ns-upload $NIGHTSCOUT_HOST $API_SECRET treatments.json upload/latest-treatments.json ) || echo \\\"No recent treatments to upload\\\"\"" - } - }, - { - "type": "alias", - "name": "format-ns-status", - "format-ns-status": { - "command": "! bash -c \"ns-status monitor/clock-zoned.json monitor/iob.json enact/suggested.json enact/enacted.json monitor/battery.json monitor/reservoir.json monitor/status.json > upload/ns-status.json\"" - } - }, - { - "upload-ns-status": { - "command": "! bash -c \"grep -q iob monitor/iob.json && find enact/ -mmin -5 -size +5c | grep -q suggested.json && openaps format-ns-status && grep -q iob upload/ns-status.json && ns-upload $NIGHTSCOUT_HOST $API_SECRET devicestatus.json upload/ns-status.json\"" - }, - "type": "alias", - "name": "upload-ns-status" - }, - { - "type": "alias", - "name": "upload", - "upload": { - "command": "! bash -c \"echo -n Upload && ( openaps upload-ns-status; openaps upload-pumphistory-entries; openaps upload-recent-treatments ) 2>/dev/null >/dev/null && echo ed\"" - } - } -] diff --git a/lib/templates/some-reports.json b/lib/templates/some-reports.json deleted file mode 100644 index ab1172a59..000000000 --- a/lib/templates/some-reports.json +++ /dev/null @@ -1,320 +0,0 @@ -[ - { - "settings/settings.json": { - "device": "oref0", - "remainder": "copy-fresher raw-pump/settings.json", - "use": "shell", - "json_default": "True", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/settings.json" - }, - { - "type": "report", - "name": "raw-pump/bg-targets-raw.json", - "raw-pump/bg-targets-raw.json": { - "device": "pump", - "use": "read_bg_targets", - "reporter": "JSON" - } - }, - { - "settings/bg-targets.json": { - "device": "units", - "to": "mg/dL", - "use": "bg_targets", - "input": "raw-pump/bg-targets-raw.json", - "reporter": "JSON" - }, - "type": "report", - "name": "settings/bg-targets.json" - }, - { - "raw-pump/insulin-sensitivities-raw.json": { - "device": "pump", - "use": "read_insulin_sensitivities", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/insulin-sensitivities-raw.json" - }, - { - "type": "report", - "name": "settings/insulin-sensitivities.json", - "settings/insulin-sensitivities.json": { - "device": "units", - "to": "mg/dL", - "use": "insulin_sensitivities", - "input": "raw-pump/insulin-sensitivities-raw.json", - "reporter": "JSON" - } - }, - { - "type": "report", - "name": "settings/selected-basal-profile.json", - "settings/selected-basal-profile.json": { - "device": "oref0", - "remainder": "copy-fresher raw-pump/selected-basal-profile.json", - "use": "shell", - "json_default": "True", - "reporter": "JSON" - } - }, - { - "raw-pump/clock-raw.json": { - "device": "pump", - "use": "read_clock", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/clock-raw.json" - }, - { - "monitor/clock.json": { - "use": "clock", - "reporter": "JSON", - "astimezone": "False", - "date": "None", - "adjust": "missing", - "timezone": "PDT", - "device": "tz", - "input": "raw-pump/clock-raw.json" - }, - "type": "report", - "name": "monitor/clock.json" - }, - { - "monitor/temp-basal-status.json": { - "device": "pump", - "use": "read_temp_basal", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/temp-basal-status.json" - }, - { - "raw-pump/pump-history-raw.json": { - "hours": "8.0", - "device": "pump", - "use": "iter_pump_hours", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/pump-history-raw.json" - }, - { - "monitor/pump-history.json": { - "use": "rezone", - "reporter": "JSON", - "astimezone": "False", - "date": "timestamp dateString start_at end_at created_at", - "adjust": "missing", - "timezone": "PDT", - "device": "tz", - "input": "raw-pump/pump-history-raw.json" - }, - "type": "report", - "name": "monitor/pump-history.json" - }, - { - "type": "report", - "name": "model.json", - "model.json": { - "device": "pump", - "use": "model", - "reporter": "JSON" - } - }, - { - "monitor/reservoir.json": { - "device": "pump", - "use": "reservoir", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/reservoir.json" - }, - { - "type": "report", - "name": "monitor/status.json", - "monitor/status.json": { - "device": "pump", - "use": "read_status", - "reporter": "JSON" - } - }, - { - "monitor/battery.json": { - "device": "pump", - "use": "read_battery_status", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/battery.json" - }, - { - "type": "report", - "name": "oref0-monitor/profile.json", - "oref0-monitor/profile.json": { - "insulin-sensitivities": "settings/insulin-sensitivities.json", - "use": "shell", - "settings": "settings/settings.json", - "reporter": "text", - "json_default": "True", - "device": "get-profile", - "bg-targets": "settings/bg-targets.json", - "basal-profile": "settings/selected-basal-profile.json", - "max-iob": "max-iob.json", - "remainder": "" - } - }, - { - "type": "report", - "name": "oref0-monitor/iob.json", - "oref0-monitor/iob.json": { - "use": "shell", - "clock": "monitor/clock.json", - "reporter": "text", - "json_default": "True", - "pump-history": "monitor/pump-history.json", - "oref0-profile": "oref0-monitor/profile.json", - "device": "calculate-iob", - "remainder": "" - } - }, - { - "type": "report", - "name": "oref0-predict/oref0.json", - "oref0-predict/oref0.json": { - "use": "shell", - "oref0-iob": "oref0-monitor/iob.json", - "temp-basal": "monitor/temp-basal-status.json", - "reporter": "text", - "json_default": "True", - "oref0-profile": "oref0-monitor/profile.json", - "device": "determine-basal", - "remainder": "", - "glucose": "monitor/glucose.json" - } - }, - { - "type": "report", - "name": "oref0-enacted/enacted-temp-basal.json", - "oref0-enacted/enacted-temp-basal.json": { - "device": "pump", - "input": "oref0-predict/oref0.json", - "use": "set_temp_basal", - "reporter": "JSON" - } - }, - { - "monitor/glucose-raw.json": { - "count": "20", - "device": "cgm", - "use": "iter_glucose", - "reporter": "JSON" - }, - "type": "report", - "name": "monitor/glucose-raw.json" - }, - { - "type": "report", - "name": "monitor/glucose.json", - "monitor/glucose.json": { - "use": "rezone", - "reporter": "JSON", - "astimezone": "False", - "date": "timestamp dateString start_at end_at created_at", - "adjust": "missing", - "timezone": "PDT", - "device": "tz", - "input": "raw-cgm/glucose-raw.json" - } - }, - { - "cgm-vendor.json": { - "device": "cgm", - "use": "GetFirmwareHeader", - "reporter": "JSON" - }, - "type": "report", - "name": "cgm-vendor.json" - }, - { - "blah.txt": { - "thing": "foo", - "use": "shell", - "reporter": "text", - "device": "pong", - "remainder": "bar", - "json_default": "False" - }, - "type": "report", - "name": "blah.txt" - }, - { - "raw-pump/settings.json": { - "device": "pump", - "use": "read_settings", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/settings.json" - }, - { - "type": "report", - "name": "raw-pump/selected-basal-profile.json", - "raw-pump/selected-basal-profile.json": { - "device": "pump", - "use": "read_selected_basal_profile", - "reporter": "JSON" - } - }, - { - "raw-pump/temp-basal-status.json": { - "device": "pump", - "use": "read_temp_basal", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/temp-basal-status.json" - }, - { - "raw-pump/reservoir.json": { - "device": "pump", - "use": "reservoir", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/reservoir.json" - }, - { - "type": "report", - "name": "raw-pump/status.json", - "raw-pump/status.json": { - "device": "pump", - "use": "read_status", - "reporter": "JSON" - } - }, - { - "raw-pump/battery.json": { - "device": "pump", - "use": "read_battery_status", - "reporter": "JSON" - }, - "type": "report", - "name": "raw-pump/battery.json" - }, - { - "type": "report", - "name": "raw-cgm/glucose-raw.json", - "raw-cgm/glucose-raw.json": { - "count": "20", - "device": "cgm", - "use": "iter_glucose", - "reporter": "JSON" - } - } -] diff --git a/package.json b/package.json index dd8f15585..21a513ae7 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,6 @@ "oref0-setup": "./bin/oref0-setup.sh", "oref0-subg-ww-radio-parameters": "./bin/oref0-subg-ww-radio-parameters.sh", "oref0_subg_ww_radio_parameters.py": "./bin/oref0_subg_ww_radio_parameters.py", - "oref0-template": "./bin/oref0-template.js", "oref0-truncate-git-history": "bin/oref0-truncate-git-history.sh", "oref0-upload-profile": "./bin/oref0-upload-profile.js", "peb-urchin-status": "./bin/peb-urchin-status.sh", From 623da1729b89def8c0b549d9a20566c872c4ae58 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Aug 2017 21:09:40 -0700 Subject: [PATCH 026/215] Decocare 0.1.0 (#597) * easy_install -U decocare * install decocare dev from source * make that 0.1.0-dev --- bin/oref0-setup.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 901e881b3..b52e2291c 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -525,6 +525,19 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then fi mkdir -p $HOME/src/ + + # TODO: remove this and switch back to easy_install or pip once decocare 0.1.0 is released + if [ -d "$HOME/src/decocare/" ]; then + echo "$HOME/src/decocare/ already exists; pulling latest 0.1.0-dev" + (cd $HOME/src/decocare && git fetch && git checkout 0.1.0-dev && git pull) || die "Couldn't pull latest decocare 0.1.0-dev" + else + echo -n "Cloning decocare 0.1.0-dev: " + (cd $HOME/src && git clone -b 0.1.0-dev git://github.com/openaps/decocare.git) || die "Couldn't clone decocare 0.1.0-dev" + fi + echo Installing decocare 0.1.0-dev + cd $HOME/src/decocare + sudo python setup.py develop || die "Couldn't install decocare 0.1.0-dev" + if [ -d "$HOME/src/oref0/" ]; then echo "$HOME/src/oref0/ already exists; pulling latest" (cd $HOME/src/oref0 && git fetch && git pull) || die "Couldn't pull latest oref0" From 65faebf46a0862b234f6b9439f95b19df3d19ac6 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Aug 2017 21:17:07 -0700 Subject: [PATCH 027/215] fix percent grep --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index bd5624d89..4cbdf61ef 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -33,7 +33,7 @@ smb_main() { if ! ( \ prep # checking to see if the log reports out that it is on % basal type, which blocks remote temps being set - if grep -q '"Temp":"percent"' monitor/temp_basal.json; then + if grep -q "percent" monitor/temp_basal.json; then echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." fi echo && echo Starting supermicrobolus pump-loop at $(date) with $upto30s second wait_for_silence: \ From 3e8eccd5263958d2b8744bb0ea61f83a150718c7 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Aug 2017 21:22:38 -0700 Subject: [PATCH 028/215] check for percent mode after failure to make it more obvious --- bin/oref0-pump-loop.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 4cbdf61ef..2c59abacf 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -20,7 +20,10 @@ main() { && touch monitor/pump_loop_completed -r monitor/pump_loop_enacted \ && echo); do - # On a random subset of failures, wait 45s and mmtune + if grep -q "percent" monitor/temp_basal.json; then + echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." + fi + # On a random subset of failures, mmtune echo Error, retrying \ && maybe_mmtune sleep 5 @@ -33,9 +36,6 @@ smb_main() { if ! ( \ prep # checking to see if the log reports out that it is on % basal type, which blocks remote temps being set - if grep -q "percent" monitor/temp_basal.json; then - echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." - fi echo && echo Starting supermicrobolus pump-loop at $(date) with $upto30s second wait_for_silence: \ && wait_for_bg \ && wait_for_silence $upto30s \ @@ -68,6 +68,9 @@ smb_main() { && echo \ ); then echo -n "SMB pump-loop failed. " + if grep -q "percent" monitor/temp_basal.json; then + echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." + fi maybe_mmtune echo Unsuccessful supermicrobolus pump-loop at $(date) fi From 07f2c884e5ba833ea5d752cedd0efd0e6b3113ef Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Aug 2017 21:33:45 -0700 Subject: [PATCH 029/215] fix whitespace --- bin/oref0-pump-loop.sh | 106 ++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 2c59abacf..8cb4711d7 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -70,7 +70,7 @@ smb_main() { echo -n "SMB pump-loop failed. " if grep -q "percent" monitor/temp_basal.json; then echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." - fi + fi maybe_mmtune echo Unsuccessful supermicrobolus pump-loop at $(date) fi @@ -254,64 +254,64 @@ function if_mdt_get_bg { if grep "MDT cgm" openaps.ini 2>&1 >/dev/null; then echo \ && echo Attempting to retrieve MDT CGM data from pump - #due to sometimes the pump is not in a state to give this command repeat until it completes - #"decocare.errors.DataTransferCorruptionError: Page size too short" - n=0 - until [ $n -ge 3 ]; do - openaps report invoke monitor/cgm-mm-glucosedirty.json 2>&1 >/dev/null && break - echo - echo CGM data retrieval from pump disrupted, retrying in 5 seconds... - n=$[$n+1] - sleep 5; - echo Reattempting to retrieve MDT CGM data - done - if [ -f "monitor/cgm-mm-glucosedirty.json" ]; then - if [ -f "cgm/glucose.json" ]; then - if [ $(date -d $(jq .[1].date monitor/cgm-mm-glucosedirty.json | tr -d '"') +%s) == $(date -d $(jq .[0].display_time monitor/glucose.json | tr -d '"') +%s) ]; then - echo MDT CGM data retrieved \ - && echo No new MDT CGM data to reformat \ - && echo - # TODO: remove if still unused at next oref0 release - # if you want to wait for new bg uncomment next lines and add a backslash after echo above - #&& wait_for_mdt_get_bg \ - #&& mdt_get_bg - else - mdt_get_bg - fi - else - mdt_get_bg - fi - else - echo "Unable to get cgm data from pump" - fi + #due to sometimes the pump is not in a state to give this command repeat until it completes + #"decocare.errors.DataTransferCorruptionError: Page size too short" + n=0 + until [ $n -ge 3 ]; do + openaps report invoke monitor/cgm-mm-glucosedirty.json 2>&1 >/dev/null && break + echo + echo CGM data retrieval from pump disrupted, retrying in 5 seconds... + n=$[$n+1] + sleep 5; + echo Reattempting to retrieve MDT CGM data + done + if [ -f "monitor/cgm-mm-glucosedirty.json" ]; then + if [ -f "cgm/glucose.json" ]; then + if [ $(date -d $(jq .[1].date monitor/cgm-mm-glucosedirty.json | tr -d '"') +%s) == $(date -d $(jq .[0].display_time monitor/glucose.json | tr -d '"') +%s) ]; then + echo MDT CGM data retrieved \ + && echo No new MDT CGM data to reformat \ + && echo + # TODO: remove if still unused at next oref0 release + # if you want to wait for new bg uncomment next lines and add a backslash after echo above + #&& wait_for_mdt_get_bg \ + #&& mdt_get_bg + else + mdt_get_bg + fi + else + mdt_get_bg + fi + else + echo "Unable to get cgm data from pump" + fi fi } # TODO: remove if still unused at next oref0 release -function wait_for_mdt_get_bg { - # This might not really be needed since very seldom does a loop take less time to run than CGM Data takes to refresh. - until [ $(date --date="@$(($(date -d $(jq .[1].date monitor/cgm-mm-glucosedirty.json| tr -d '"') +%s) + 300))" +%s) -lt $(date +%s) ]; do - CGMDIFFTIME=$(( $(date --date="@$(($(date -d $(jq .[1].date monitor/cgm-mm-glucosedirty.json| tr -d '"') +%s) + 300))" +%s) - $(date +%s) )) - echo "Last CGM Time was $(date -d $(jq .[1].date monitor/cgm-mm-glucosedirty.json| tr -d '"') +"%r") wait untill $(date --date="@$(($(date #-d $(jq .[1].date monitor/cgm-mm-glucosedirty.json| tr -d '"') +%s) + 300))" +"%r")to continue" - echo "waiting for $CGMDIFFTIME seconds before continuing" - sleep $CGMDIFFTIME - until openaps report invoke monitor/cgm-mm-glucosedirty.json 2>&1 >/dev/null; do - echo cgm data from pump disrupted, retrying in 5 seconds... - sleep 5; - echo -n MDT cgm data retrieve - done - done +function wait_for_mdt_get_bg { + # This might not really be needed since very seldom does a loop take less time to run than CGM Data takes to refresh. + until [ $(date --date="@$(($(date -d $(jq .[1].date monitor/cgm-mm-glucosedirty.json| tr -d '"') +%s) + 300))" +%s) -lt $(date +%s) ]; do + CGMDIFFTIME=$(( $(date --date="@$(($(date -d $(jq .[1].date monitor/cgm-mm-glucosedirty.json| tr -d '"') +%s) + 300))" +%s) - $(date +%s) )) + echo "Last CGM Time was $(date -d $(jq .[1].date monitor/cgm-mm-glucosedirty.json| tr -d '"') +"%r") wait untill $(date --date="@$(($(date #-d $(jq .[1].date monitor/cgm-mm-glucosedirty.json| tr -d '"') +%s) + 300))" +"%r")to continue" + echo "waiting for $CGMDIFFTIME seconds before continuing" + sleep $CGMDIFFTIME + until openaps report invoke monitor/cgm-mm-glucosedirty.json 2>&1 >/dev/null; do + echo cgm data from pump disrupted, retrying in 5 seconds... + sleep 5; + echo -n MDT cgm data retrieve + done + done } function mdt_get_bg { openaps report invoke monitor/cgm-mm-glucosetrend.json 2>&1 >/dev/null \ - && openaps report invoke cgm/cgm-glucose.json 2>&1 >/dev/null \ - && grep -q glucose cgm/cgm-glucose.json \ - && echo MDT CGM data retrieved \ - && cp -pu cgm/cgm-glucose.json cgm/glucose.json \ - && cp -pu cgm/glucose.json monitor/glucose-unzoned.json \ - && echo -n MDT New cgm data reformat \ - && openaps report invoke monitor/glucose.json 2>&1 >/dev/null \ - && openaps report invoke nightscout/glucose.json 2>&1 >/dev/null \ - && echo ted + && openaps report invoke cgm/cgm-glucose.json 2>&1 >/dev/null \ + && grep -q glucose cgm/cgm-glucose.json \ + && echo MDT CGM data retrieved \ + && cp -pu cgm/cgm-glucose.json cgm/glucose.json \ + && cp -pu cgm/glucose.json monitor/glucose-unzoned.json \ + && echo -n MDT New cgm data reformat \ + && openaps report invoke monitor/glucose.json 2>&1 >/dev/null \ + && openaps report invoke nightscout/glucose.json 2>&1 >/dev/null \ + && echo ted } # make sure we can talk to the pump and get a valid model number function preflight { From 62b527bee821f5f0f2d42d63aa32d1d557a3e62c Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Aug 2017 21:46:36 -0700 Subject: [PATCH 030/215] stop using DIA for anything but actual IOB/activity calcs (#599) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix require() statements to work with Node 8 * Change to determine_basal that exposes behavior changes * Oops can’t do that simplification * Fiasp curve * removed debug logging * peak configuration, support old bilinear model * Changes to code structure, more tests * Revert a require() change that was included accidentally * Another change revert, needs testing outside the scope of Fiasp * Removing accidental formatting changes * Force IOB to 0 if over 5 hours have passed. Added tests, support for Novo peak scaling. AUC normalized for activity. * Renamed the curves for consistency * Small speedup to IOB calculation, use consistent date value if missing, added default curve to profile to ensure the correct curve is used * New generic curves * Corrected error logging * simply calculate biobContrib using 2t instead of t * Fixed bolus snooze test data to match the new calculation method * unit test for COB calculation - note the math is unverified. New logic for ISF fetching. Bug fix COB calculation if only one event is presented. Sort glucose data to match later logic assumptions. * Testing if removing package-lock.json fixes the build * Testing relative require paths in case that makes the server happy, fixed formatting * Fix test name, add travis build with Node 8 * Revert "Merge branch 'cob-test' into 0.6.0-dev" This reverts commit 72a60d90d8805f0904630fc6a5863d078ab6cbe6, reversing changes made to 547376a45684771161de4e9b637d1b835d089ed9. Conflicts: lib/iob/total.js * chmod +x bin/oref0_nightscout_check.py * if currentDeviation is null or maxDeviation is 0, set mealCOB to 0 for zombie-carb safety (#589) * stop using DIA for anything but actual IOB/activity calcs * reset DIA to 5h silently if needed * get treatments from pumphistory once, not every time we get_iob() * get treatments from pumphistory once, not every time we get_iob() * speed up COB calculation * Speed up COB calculation by only converting pumphistory to treatments once (#603) * get treatments from pumphistory once, not every time we get_iob() * get treatments from pumphistory once, not every time we get_iob() * syntax * update tests --- bin/oref0-meal.js | 4 ++-- lib/determine-basal/determine-basal.js | 24 ++++++++++++------------ lib/iob/calculate.js | 2 +- lib/meal/total.js | 4 ++-- tests/determine-basal.test.js | 5 +++-- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/bin/oref0-meal.js b/bin/oref0-meal.js index b54d68306..933e04f66 100755 --- a/bin/oref0-meal.js +++ b/bin/oref0-meal.js @@ -99,7 +99,7 @@ if (!module.parent) { , glucose: glucose_data }; - var dia_carbs = generate(inputs); - console.log(JSON.stringify(dia_carbs)); + var recentCarbs = generate(inputs); + console.log(JSON.stringify(recentCarbs)); } diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index d9e1fb666..76c40c82f 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -26,12 +26,12 @@ function round(value, digits) // we expect BG to rise or fall at the rate of BGI, // adjusted by the rate at which BG would need to rise / -// fall to get eventualBG to target over DIA/2 hours -function calculate_expected_delta(dia, target_bg, eventual_bg, bgi) { - // (hours * mins_per_hour) / 5 = how many 5 minute periods in dia/2 - var dia_in_5min_blocks = (dia/2 * 60) / 5; +// fall to get eventualBG to target over 2 hours +function calculate_expected_delta(target_bg, eventual_bg, bgi) { + // (hours * mins_per_hour) / 5 = how many 5 minute periods in 2h = 24 + var five_min_blocks = (2 * 60) / 5; var target_delta = target_bg - eventual_bg; - var expectedDelta = round(bgi + (target_delta / dia_in_5min_blocks), 1); + var expectedDelta = round(bgi + (target_delta / five_min_blocks), 1); return expectedDelta; } @@ -215,7 +215,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } } - var expectedDelta = calculate_expected_delta(profile.dia, target_bg, eventualBG, bgi); + var expectedDelta = calculate_expected_delta(target_bg, eventualBG, bgi); if (typeof eventualBG === 'undefined' || isNaN(eventualBG)) { rT.error ='Error: could not calculate eventualBG. '; return rT; @@ -234,7 +234,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ , 'eventualBG': eventualBG , 'snoozeBG': snoozeBG , 'insulinReq': 0 - , 'reservoir' : reservoir_data // The expected reservoir volume at which to deliver the microbolus (the reservoir volume from immediately before the last pumphistory run) + , 'reservoir' : reservoir_data // The expected reservoir volume at which to deliver the microbolus (the reservoir volume from right before the last pumphistory run) , 'deliverAt' : deliverAt // The time at which the microbolus should be delivered , 'minPredBG' : 999 }; @@ -256,7 +256,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ UAMpredBGs.push(bg); // enable SMB whenever we have COB or UAM is enabled - // SMB is diabled by default, unless explicitly enabled in preferences.json + // SMB is disabled by default, unless explicitly enabled in preferences.json var enableSMB=false; // disable SMB when a high temptarget is set if (profile.temptargetSet && target_bg > 100) { @@ -362,11 +362,11 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // calculate predicted CI from UAM based on minDeviationSlope predUCIslope = Math.max(0, uci + ( UAMpredBGs.length*minDeviationSlope ) ); // if minDeviationSlope is too flat, predicted deviation impact drops linearly from - // current deviation down to zero over DIA (data points every 5m) - predUCIdia = Math.max(0, uci * ( 1 - UAMpredBGs.length/Math.max(profile.dia*60/5,1) ) ); - //console.error(predUCIslope, predUCIdia); + // current deviation down to zero over 3h (data points every 5m) + predUCImax = Math.max(0, uci * ( 1 - UAMpredBGs.length/Math.max(3*60/5,1) ) ); + //console.error(predUCIslope, predUCImax); // predicted CI from UAM is the lesser of CI based on deviationSlope or DIA - predUCI = Math.min(predUCIslope, predUCIdia); + predUCI = Math.min(predUCIslope, predUCImax); if(predUCI>0) { //console.error(UAMpredBGs.length,minDeviationSlope, predUCI); UAMduration=round((UAMpredBGs.length+1)*5/60,1); diff --git a/lib/iob/calculate.js b/lib/iob/calculate.js index 307ae85e0..e0de8d545 100644 --- a/lib/iob/calculate.js +++ b/lib/iob/calculate.js @@ -101,7 +101,7 @@ function iobCalc(treatment, time, dia, profile) { var td = dia * 60; if (defaults.requireLongDia && dia < 5) { - console.error('Pump DIA must be set to 5 hours or more with the new curves, please adjust your pump. Defaulting to 5 hour DIA.'); + //console.error('Pump DIA must be set to 5 hours or more with the new curves, please adjust your pump. Defaulting to 5 hour DIA.'); td = 300; } diff --git a/lib/meal/total.js b/lib/meal/total.js index 739b3249c..5f5c7d00a 100644 --- a/lib/meal/total.js +++ b/lib/meal/total.js @@ -1,7 +1,7 @@ var tz = require('moment-timezone'); var calcMealCOB = require('oref0/lib/determine-basal/cob-autosens'); -function diaCarbs(opts, time) { +function recentCarbs(opts, time) { var treatments = opts.treatments; var profile_data = opts.profile; if (typeof(opts.glucose) !== 'undefined') { @@ -88,5 +88,5 @@ function diaCarbs(opts, time) { }; } -exports = module.exports = diaCarbs; +exports = module.exports = recentCarbs; diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js index 59cae5a60..d8f833a19 100644 --- a/tests/determine-basal.test.js +++ b/tests/determine-basal.test.js @@ -432,9 +432,10 @@ describe('determine-basal', function ( ) { }); it('should set lower high-temp when high and falling almost fast enough with low insulin activity', function () { - var glucose_status = {"delta":-8,"glucose":300,"long_avgdelta":-5,"short_avgdelta":-5}; + var glucose_status = {"delta":-6,"glucose":300,"long_avgdelta":-5,"short_avgdelta":-5}; var iob_data = {"iob":0.5,"activity":0.005,"bolussnooze":0}; var output = determine_basal(glucose_status, currenttemp, iob_data, profile, undefined, meal_data, tempBasalFunctions); + console.error(output); output.rate.should.be.above(1); output.rate.should.be.below(2); output.duration.should.equal(30); @@ -442,7 +443,7 @@ describe('determine-basal', function ( ) { }); it('should reduce high-temp when high and falling almost fast enough with low insulin activity', function () { - var glucose_status = {"delta":-8,"glucose":300,"long_avgdelta":-5,"short_avgdelta":-5}; + var glucose_status = {"delta":-6,"glucose":300,"long_avgdelta":-5,"short_avgdelta":-5}; var iob_data = {"iob":0.5,"activity":0.005,"bolussnooze":0}; var currenttemp = {"duration":30,"rate":3.5,"temp":"absolute"}; var output = determine_basal(glucose_status, currenttemp, iob_data, profile, undefined, meal_data, tempBasalFunctions); From 82d0b250b6eb8e6598308d5114852be30c56ddd3 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Aug 2017 22:35:37 -0700 Subject: [PATCH 031/215] don't allow target_bg below 80 --- lib/determine-basal/determine-basal.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 76c40c82f..9421a5fa6 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -111,6 +111,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ min_bg = round((min_bg - 60) / autosens_data.ratio) + 60; max_bg = round((max_bg - 60) / autosens_data.ratio) + 60; new_target_bg = round((target_bg - 60) / autosens_data.ratio) + 60; + // don't allow target_bg below 80 + new_target_bg = Math.max(80, new_target_bg); if (target_bg == new_target_bg) { process.stderr.write("target_bg unchanged: "+new_target_bg+"; "); } else { From 18b066d8b759d991cf3456b6659ff21b6f7c4ce4 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Aug 2017 22:46:11 -0700 Subject: [PATCH 032/215] only updatePreferences with displayedDefaults --- bin/oref0-get-profile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/oref0-get-profile.js b/bin/oref0-get-profile.js index bee4f4807..bec4cf1b3 100755 --- a/bin/oref0-get-profile.js +++ b/bin/oref0-get-profile.js @@ -27,9 +27,9 @@ function exportDefaults () { } function updatePreferences (prefs) { - var defaults = generate.defaults(); + var defaults = generate.displayedDefaults(); - // check for any keys missing from current prefs and add from defaults + // check for any displayedDefaults missing from current prefs and add from defaults for (var pref in defaults) { if (defaults.hasOwnProperty(pref) && !prefs.hasOwnProperty(pref)) { From e2ee0a6f355fb4dce57c74f7933021d1681627eb Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 13 Aug 2017 23:04:19 -0700 Subject: [PATCH 033/215] move dia = 3 code so not to interfere with bolus snooze --- lib/iob/total.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/iob/total.js b/lib/iob/total.js index 2c01c5a52..8226f28ca 100644 --- a/lib/iob/total.js +++ b/lib/iob/total.js @@ -20,6 +20,11 @@ function iobTotal(opts, time) { treatments.forEach(function(treatment) { if(treatment.date <= time.getTime( )) { var dia = profile_data.dia; + // force minimum DIA of 3h + if (dia < 3) { + console.error("Warning; adjusting DIA from",dia,"to minimum of 3 hours"); + dia = 3; + } var dia_ago = now - profile_data.dia*60*60*1000; // tIOB = total IOB var tIOB = iobCalc(treatment, time, dia, profile_data); From f4a96246987d0b75c83f50e825e34dc9d55caec4 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Fri, 18 Aug 2017 20:15:58 -0700 Subject: [PATCH 034/215] use profile.sens instead of autosens-adjusted sens (#618) --- lib/determine-basal/determine-basal.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 9421a5fa6..053eeaa8b 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -290,7 +290,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ ci = round((minDelta - bgi),1); uci = round((minAvgDelta - bgi),1); // ISF (mg/dL/U) / CR (g/U) = CSF (mg/dL/g) - var csf = sens / profile.carb_ratio + // use profile.sens instead of autosens-adjusted sens to avoid counteracting + // autosens meal insulin dosing adjustmenst when sensitive/resistant + var csf = profile.sens / profile.carb_ratio // set meal_carbimpact high enough to absorb all meal carbs over 6 hours // total_impact (mg/dL) = CSF (mg/dL/g) * carbs (g) //console.error(csf * meal_data.carbs); From fa58b80f5b0550c7196fb580193d8cf1c38bcf96 Mon Sep 17 00:00:00 2001 From: jsmurray1 Date: Sun, 20 Aug 2017 17:04:20 -0400 Subject: [PATCH 035/215] Move Edison refs to Explorer IF/Then section An attmept to reduce problems on Pi based rigs by moving Edison references to the Explorer If/Then section of the setup. --- bin/oref0-setup.sh | 50 ++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 86181d5e4..5c9a211e5 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -1,7 +1,7 @@ #!/bin/bash # This script sets up an openaps environment by defining the required devices, -# reports, and aliases, and optionally enabling it in cron, +# reports, and aliases, and optionally enabling it in cron, # plus editing other user-entered configuration settings. # Released under MIT license. See the accompanying LICENSE.txt file for # full terms and conditions @@ -190,6 +190,29 @@ if [[ -z "$DIR" || -z "$serial" ]]; then ttyport=/dev/spidev5.1 echocolor "Ok, yay for Explorer Board! " echo + # Install EdisonVoltage + if egrep -i "edison" /etc/passwd 2>/dev/null; then + echo "Checking if EdisonVoltage is already installed" + if [ -d "$HOME/src/EdisonVoltage/" ]; then + echo "EdisonVoltage already installed" + else + echo "Installing EdisonVoltage" + cd $HOME/src && git clone -b master git://github.com/cjo20/EdisonVoltage.git || (cd EdisonVoltage && git checkout master && git pull) + cd $HOME/src/EdisonVoltage + make voltage + fi + # Add module needed for EdisonVoltage to work on jubilinux 0.2.0 + grep iio_basincove_gpadc /etc/modules-load.d/modules.conf || echo iio_basincove_gpadc >> /etc/modules-load.d/modules.conf + cd $directory || die "Can't cd $directory" + for type in edisonbattery; do + echo importing $type file + cat $HOME/src/oref0/lib/oref0-setup/$type.json | openaps import || die "Could not import $type.json" + done + fi + # proper shutdown once the EdisonVoltage very low (< 3050mV; 2950 is dead) + if egrep -i "edison" /etc/passwd 2>/dev/null; then + (crontab -l; crontab -l | grep -q "cd $directory && openaps battery-status" || echo "*/15 * * * * cd $directory && openaps battery-status; cat $directory/monitor/edison-battery.json | json batteryVoltage | awk '{if (\$1<=3050)system(\"sudo shutdown -h now\")}'") | crontab - + fi else read -p 'Are you using mmeowlink (i.e. with a TI stick)? If not, press enter. If so, what TTY port (full port address, looks like "/dev/ttySOMETHING" without the quotes - you probably want to copy paste it)? ' -r ttyport=$REPLY @@ -830,25 +853,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then touch /tmp/reboot-required fi - # Install EdisonVoltage - if egrep -i "edison" /etc/passwd 2>/dev/null; then - echo "Checking if EdisonVoltage is already installed" - if [ -d "$HOME/src/EdisonVoltage/" ]; then - echo "EdisonVoltage already installed" - else - echo "Installing EdisonVoltage" - cd $HOME/src && git clone -b master git://github.com/cjo20/EdisonVoltage.git || (cd EdisonVoltage && git checkout master && git pull) - cd $HOME/src/EdisonVoltage - make voltage - fi - # Add module needed for EdisonVoltage to work on jubilinux 0.2.0 - grep iio_basincove_gpadc /etc/modules-load.d/modules.conf || echo iio_basincove_gpadc >> /etc/modules-load.d/modules.conf - cd $directory || die "Can't cd $directory" - for type in edisonbattery; do - echo importing $type file - cat $HOME/src/oref0/lib/oref0-setup/$type.json | openaps import || die "Could not import $type.json" - done - fi + # Install Pancreabble echo Checking for BT Pebble Mac if [[ ! -z "$BT_PEB" ]]; then @@ -997,10 +1002,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ ! -z "$BT_PEB" || ! -z "$BT_MAC" ]]; then (crontab -l; crontab -l | grep -q "oref0-bluetoothup" || echo '* * * * * ps aux | grep -v grep | grep -q "oref0-bluetoothup" || oref0-bluetoothup >> /var/log/openaps/network.log' ) | crontab - fi - # proper shutdown once the EdisonVoltage very low (< 3050mV; 2950 is dead) - if egrep -i "edison" /etc/passwd 2>/dev/null; then - (crontab -l; crontab -l | grep -q "cd $directory && openaps battery-status" || echo "*/15 * * * * cd $directory && openaps battery-status; cat $directory/monitor/edison-battery.json | json batteryVoltage | awk '{if (\$1<=3050)system(\"sudo shutdown -h now\")}'") | crontab - - fi + (crontab -l; crontab -l | grep -q "cd $directory && oref0-delete-future-entries" || echo "@reboot cd $directory && oref0-delete-future-entries") | crontab - if [[ ! -z "$PUSHOVER_TOKEN" && ! -z "$PUSHOVER_USER" ]]; then (crontab -l; crontab -l | grep -q "oref0-pushover" || echo "* * * * * cd $directory && oref0-pushover $PUSHOVER_TOKEN $PUSHOVER_USER 2>&1 >> /var/log/openaps/pushover.log" ) | crontab - From e696d1a7371ff7d877e5f0a52576e7e5c960414a Mon Sep 17 00:00:00 2001 From: jsmurray1 Date: Sun, 20 Aug 2017 19:07:33 -0400 Subject: [PATCH 036/215] Added user check to verify existance of edison before adding to groups. --- bin/openaps-install.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bin/openaps-install.sh b/bin/openaps-install.sh index cf890daf6..08ef733f6 100644 --- a/bin/openaps-install.sh +++ b/bin/openaps-install.sh @@ -18,8 +18,16 @@ dpkg-reconfigure tzdata # TODO: remove the `-o Acquire::ForceIPv4=true` once Debian's mirrors work reliably over IPv6 apt-get -o Acquire::ForceIPv4=true update && apt-get -o Acquire::ForceIPv4=true -y dist-upgrade && apt-get -o Acquire::ForceIPv4=true -y autoremove apt-get -o Acquire::ForceIPv4=true install -y sudo strace tcpdump screen acpid vim python-pip locate -adduser edison sudo -adduser edison dialout +#check if edison user exists before trying to add it to groups + +if getent passwd edison > /dev/null; then + echo "Adding edison to sudo users" + adduser edison sudo + echo "Adding edison to dialout users" + adduser edison dialout + else + echo "User edison does not exist. Apparently, you are runnning a non-edison setup." +fi sed -i "s/daily/hourly/g" /etc/logrotate.conf sed -i "s/#compress/compress/g" /etc/logrotate.conf From 3e96e5865ebdce31a3cedb1e0d42311d0e4626c6 Mon Sep 17 00:00:00 2001 From: jsmurray1 Date: Sun, 20 Aug 2017 19:35:09 -0400 Subject: [PATCH 037/215] Revert "Move Edison refs to Explorer IF/Then section" This reverts commit fa58b80f5b0550c7196fb580193d8cf1c38bcf96. --- bin/oref0-setup.sh | 50 ++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 5c9a211e5..86181d5e4 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -1,7 +1,7 @@ #!/bin/bash # This script sets up an openaps environment by defining the required devices, -# reports, and aliases, and optionally enabling it in cron, +# reports, and aliases, and optionally enabling it in cron, # plus editing other user-entered configuration settings. # Released under MIT license. See the accompanying LICENSE.txt file for # full terms and conditions @@ -190,29 +190,6 @@ if [[ -z "$DIR" || -z "$serial" ]]; then ttyport=/dev/spidev5.1 echocolor "Ok, yay for Explorer Board! " echo - # Install EdisonVoltage - if egrep -i "edison" /etc/passwd 2>/dev/null; then - echo "Checking if EdisonVoltage is already installed" - if [ -d "$HOME/src/EdisonVoltage/" ]; then - echo "EdisonVoltage already installed" - else - echo "Installing EdisonVoltage" - cd $HOME/src && git clone -b master git://github.com/cjo20/EdisonVoltage.git || (cd EdisonVoltage && git checkout master && git pull) - cd $HOME/src/EdisonVoltage - make voltage - fi - # Add module needed for EdisonVoltage to work on jubilinux 0.2.0 - grep iio_basincove_gpadc /etc/modules-load.d/modules.conf || echo iio_basincove_gpadc >> /etc/modules-load.d/modules.conf - cd $directory || die "Can't cd $directory" - for type in edisonbattery; do - echo importing $type file - cat $HOME/src/oref0/lib/oref0-setup/$type.json | openaps import || die "Could not import $type.json" - done - fi - # proper shutdown once the EdisonVoltage very low (< 3050mV; 2950 is dead) - if egrep -i "edison" /etc/passwd 2>/dev/null; then - (crontab -l; crontab -l | grep -q "cd $directory && openaps battery-status" || echo "*/15 * * * * cd $directory && openaps battery-status; cat $directory/monitor/edison-battery.json | json batteryVoltage | awk '{if (\$1<=3050)system(\"sudo shutdown -h now\")}'") | crontab - - fi else read -p 'Are you using mmeowlink (i.e. with a TI stick)? If not, press enter. If so, what TTY port (full port address, looks like "/dev/ttySOMETHING" without the quotes - you probably want to copy paste it)? ' -r ttyport=$REPLY @@ -853,7 +830,25 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then touch /tmp/reboot-required fi - + # Install EdisonVoltage + if egrep -i "edison" /etc/passwd 2>/dev/null; then + echo "Checking if EdisonVoltage is already installed" + if [ -d "$HOME/src/EdisonVoltage/" ]; then + echo "EdisonVoltage already installed" + else + echo "Installing EdisonVoltage" + cd $HOME/src && git clone -b master git://github.com/cjo20/EdisonVoltage.git || (cd EdisonVoltage && git checkout master && git pull) + cd $HOME/src/EdisonVoltage + make voltage + fi + # Add module needed for EdisonVoltage to work on jubilinux 0.2.0 + grep iio_basincove_gpadc /etc/modules-load.d/modules.conf || echo iio_basincove_gpadc >> /etc/modules-load.d/modules.conf + cd $directory || die "Can't cd $directory" + for type in edisonbattery; do + echo importing $type file + cat $HOME/src/oref0/lib/oref0-setup/$type.json | openaps import || die "Could not import $type.json" + done + fi # Install Pancreabble echo Checking for BT Pebble Mac if [[ ! -z "$BT_PEB" ]]; then @@ -1002,7 +997,10 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ ! -z "$BT_PEB" || ! -z "$BT_MAC" ]]; then (crontab -l; crontab -l | grep -q "oref0-bluetoothup" || echo '* * * * * ps aux | grep -v grep | grep -q "oref0-bluetoothup" || oref0-bluetoothup >> /var/log/openaps/network.log' ) | crontab - fi - + # proper shutdown once the EdisonVoltage very low (< 3050mV; 2950 is dead) + if egrep -i "edison" /etc/passwd 2>/dev/null; then + (crontab -l; crontab -l | grep -q "cd $directory && openaps battery-status" || echo "*/15 * * * * cd $directory && openaps battery-status; cat $directory/monitor/edison-battery.json | json batteryVoltage | awk '{if (\$1<=3050)system(\"sudo shutdown -h now\")}'") | crontab - + fi (crontab -l; crontab -l | grep -q "cd $directory && oref0-delete-future-entries" || echo "@reboot cd $directory && oref0-delete-future-entries") | crontab - if [[ ! -z "$PUSHOVER_TOKEN" && ! -z "$PUSHOVER_USER" ]]; then (crontab -l; crontab -l | grep -q "oref0-pushover" || echo "* * * * * cd $directory && oref0-pushover $PUSHOVER_TOKEN $PUSHOVER_USER 2>&1 >> /var/log/openaps/pushover.log" ) | crontab - From 98051f66ee119f6a35aed52ffa046bae10bdbaa8 Mon Sep 17 00:00:00 2001 From: jsmurray1 Date: Sun, 20 Aug 2017 19:47:34 -0400 Subject: [PATCH 038/215] 2nd attempt to only run edison battery stuff on edison rigs. --- bin/oref0-setup.sh | 48 ++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 86181d5e4..1f50741f3 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -1,7 +1,7 @@ #!/bin/bash # This script sets up an openaps environment by defining the required devices, -# reports, and aliases, and optionally enabling it in cron, +# reports, and aliases, and optionally enabling it in cron, # plus editing other user-entered configuration settings. # Released under MIT license. See the accompanying LICENSE.txt file for # full terms and conditions @@ -26,6 +26,7 @@ DIR="" directory="" EXTRAS="" radio_locale="US" +explorer1="NO" #this makes the confirmation echo text a color when you use echocolor instead of echo function echocolor() { # $1 = string @@ -188,6 +189,7 @@ if [[ -z "$DIR" || -z "$serial" ]]; then read -p "Are you using an Explorer Board? y/[N] " -r if [[ $REPLY =~ ^[Yy]$ ]]; then ttyport=/dev/spidev5.1 + explorer1="YES" echocolor "Ok, yay for Explorer Board! " echo else @@ -831,23 +833,25 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then fi # Install EdisonVoltage - if egrep -i "edison" /etc/passwd 2>/dev/null; then - echo "Checking if EdisonVoltage is already installed" - if [ -d "$HOME/src/EdisonVoltage/" ]; then - echo "EdisonVoltage already installed" - else - echo "Installing EdisonVoltage" - cd $HOME/src && git clone -b master git://github.com/cjo20/EdisonVoltage.git || (cd EdisonVoltage && git checkout master && git pull) - cd $HOME/src/EdisonVoltage - make voltage - fi - # Add module needed for EdisonVoltage to work on jubilinux 0.2.0 - grep iio_basincove_gpadc /etc/modules-load.d/modules.conf || echo iio_basincove_gpadc >> /etc/modules-load.d/modules.conf - cd $directory || die "Can't cd $directory" - for type in edisonbattery; do - echo importing $type file - cat $HOME/src/oref0/lib/oref0-setup/$type.json | openaps import || die "Could not import $type.json" - done + if explorer1 == "YES"; then + if egrep -i "edison" /etc/passwd 2>/dev/null; then + echo "Checking if EdisonVoltage is already installed" + if [ -d "$HOME/src/EdisonVoltage/" ]; then + echo "EdisonVoltage already installed" + else + echo "Installing EdisonVoltage" + cd $HOME/src && git clone -b master git://github.com/cjo20/EdisonVoltage.git || (cd EdisonVoltage && git checkout master && git pull) + cd $HOME/src/EdisonVoltage + make voltage + fi + # Add module needed for EdisonVoltage to work on jubilinux 0.2.0 + grep iio_basincove_gpadc /etc/modules-load.d/modules.conf || echo iio_basincove_gpadc >> /etc/modules-load.d/modules.conf + cd $directory || die "Can't cd $directory" + for type in edisonbattery; do + echo importing $type file + cat $HOME/src/oref0/lib/oref0-setup/$type.json | openaps import || die "Could not import $type.json" + done + fi fi # Install Pancreabble echo Checking for BT Pebble Mac @@ -997,9 +1001,11 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ ! -z "$BT_PEB" || ! -z "$BT_MAC" ]]; then (crontab -l; crontab -l | grep -q "oref0-bluetoothup" || echo '* * * * * ps aux | grep -v grep | grep -q "oref0-bluetoothup" || oref0-bluetoothup >> /var/log/openaps/network.log' ) | crontab - fi - # proper shutdown once the EdisonVoltage very low (< 3050mV; 2950 is dead) - if egrep -i "edison" /etc/passwd 2>/dev/null; then - (crontab -l; crontab -l | grep -q "cd $directory && openaps battery-status" || echo "*/15 * * * * cd $directory && openaps battery-status; cat $directory/monitor/edison-battery.json | json batteryVoltage | awk '{if (\$1<=3050)system(\"sudo shutdown -h now\")}'") | crontab - + if explorer1 == "YES"; then + # proper shutdown once the EdisonVoltage very low (< 3050mV; 2950 is dead) + if egrep -i "edison" /etc/passwd 2>/dev/null; then + (crontab -l; crontab -l | grep -q "cd $directory && openaps battery-status" || echo "*/15 * * * * cd $directory && openaps battery-status; cat $directory/monitor/edison-battery.json | json batteryVoltage | awk '{if (\$1<=3050)system(\"sudo shutdown -h now\")}'") | crontab - + fi fi (crontab -l; crontab -l | grep -q "cd $directory && oref0-delete-future-entries" || echo "@reboot cd $directory && oref0-delete-future-entries") | crontab - if [[ ! -z "$PUSHOVER_TOKEN" && ! -z "$PUSHOVER_USER" ]]; then From 9a604ceeb1b41fe8e4408f0e1c59c6e53ac5c302 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 21 Aug 2017 15:12:41 -0700 Subject: [PATCH 039/215] only print minDelta < expectedDelta when it's true --- lib/determine-basal/determine-basal.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 053eeaa8b..a4bc60de0 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -575,7 +575,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ rT.reason += "BG " + convert_bg(bg, profile) + "<" + convert_bg(threshold, profile); if ((glucose_status.delta <= 0 && minDelta <= 0) || (glucose_status.delta < expectedDelta && minDelta < expectedDelta) || bg < 60 ) { // BG is still falling / rising slower than predicted - rT.reason += ", minDelta " + minDelta + " < " + "expectedDelta " + expectedDelta + "; "; + if ( minDelta < expectedDelta ) { + rT.reason += ", minDelta " + minDelta + " < " + "expectedDelta " + expectedDelta + "; "; + } return tempBasalFunctions.setTempBasal(0, 30, profile, rT, currenttemp); } if (glucose_status.delta > minDelta) { From dd6e1a64aa4d7294858620c0089dae27f1d14cd4 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 23 Aug 2017 13:35:02 -0700 Subject: [PATCH 040/215] don't overreact to negative deviations from a big negative delta (#615) --- lib/determine-basal/determine-basal.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index a4bc60de0..823f40b49 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -170,6 +170,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // don't overreact to a big negative delta: use minAvgDelta if deviation is negative if (deviation < 0) { deviation = round( (30 / 5) * ( minAvgDelta - bgi ) ); + // and if deviation is still negative, use long_avgdelta + if (deviation < 0) { + deviation = round( (30 / 5) * ( glucose_status.long_avgdelta - bgi ) ); + } } // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity From 159b4dafa1871fba70c465fe5c88155f2fd927d8 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 23 Aug 2017 13:36:37 -0700 Subject: [PATCH 041/215] make carbsReqThreshold configurable (#607) --- lib/determine-basal/determine-basal.js | 2 +- lib/profile/index.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 823f40b49..e416a5b4f 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -565,7 +565,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ zeroTempEffect = round(zeroTempEffect); carbsReq = round(carbsReq); console.error("bgUndershoot:",bgUndershoot,"zeroTempDuration:",zeroTempDuration,"zeroTempEffect:",zeroTempEffect,"carbsReq:",carbsReq); - if ( carbsReq > 0 ) { + if ( carbsReq >= profile.carbsReqThreshold ) { rT.carbsReq = carbsReq; rT.reason += carbsReq + " add'l carbs req + " + minutesAboveMinBG + "m zero temp; "; } diff --git a/lib/profile/index.js b/lib/profile/index.js index 9f6932a92..3d3a47f91 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -37,6 +37,7 @@ function defaults ( ) { , curve: "bilinear" , useCustomPeakTime: false , insulinPeakTime: 75 + , carbsReqThreshold: 1 }; return profile; } From 6cb71c1409abec87d9810dd55e1d61d9d7f4175b Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 23 Aug 2017 13:37:16 -0700 Subject: [PATCH 042/215] force minimum DIA of 3h (#606) * force minimum DIA of 3h * move dia = 3 code so not to interfere with bolus snooze From e355b0c96979d15a1bd36e8ef6ddf66be2c5e9c4 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 23 Aug 2017 13:42:15 -0700 Subject: [PATCH 043/215] Timezone fix to 0.6.0-dev (#624) * use UTC time for date string compare * make carbhistory lookback 18h --- bin/nightscout.sh | 6 +++--- lib/oref0-setup/report.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/nightscout.sh b/bin/nightscout.sh index 1a78ec023..1de21d2da 100755 --- a/bin/nightscout.sh +++ b/bin/nightscout.sh @@ -292,11 +292,11 @@ ns) ;; temp_targets) expr=${1--24hours} - exec ns-get host $NIGHTSCOUT_HOST treatments.json "find[created_at][\$gte]=$(date -d $expr -Iminutes)&find[eventType]=Temporary+Target" + exec ns-get host $NIGHTSCOUT_HOST treatments.json "find[created_at][\$gte]=$(date -d $expr -Iminutes -u)&find[eventType]=Temporary+Target" ;; carb_history) expr=${1--24hours} - exec ns-get host $NIGHTSCOUT_HOST treatments.json "find[created_at][\$gte]=$(date -d $expr -Iminutes)&find[carbs][\$exists]=true" + exec ns-get host $NIGHTSCOUT_HOST treatments.json "find[created_at][\$gte]=$(date -d $expr -Iminutes -u)&find[carbs][\$exists]=true" ;; *) echo "Unknown request:" $OP @@ -352,4 +352,4 @@ help|--help|-h) *) test -n "$COMMAND" && exec $COMMAND $* ;; -esac \ No newline at end of file +esac diff --git a/lib/oref0-setup/report.json b/lib/oref0-setup/report.json index 498a3cb23..38586c5c2 100644 --- a/lib/oref0-setup/report.json +++ b/lib/oref0-setup/report.json @@ -18,7 +18,7 @@ "use": "shell", "reporter": "JSON", "device": "ns", - "remainder": "-6hours", + "remainder": "-18hours", "json_default": "True" }, "name": "monitor/carbhistory.json" From 112b1439aa4b6ef5e8f77a755dbbf1dd6e3aca85 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 23 Aug 2017 21:01:58 -0700 Subject: [PATCH 044/215] ignore bolusing status if pump is suspended --- bin/oref0-pump-loop.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 8cb4711d7..644c38119 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -387,7 +387,8 @@ function wait_for_silence { function gather { openaps report invoke monitor/status.json 2>&1 >/dev/null | tail -1 \ && echo -n Ref \ - && test $(cat monitor/status.json | json bolusing) == false \ + && ( test $(cat monitor/status.json | json suspended) == true || \ + test $(cat monitor/status.json | json bolusing) == false ) \ && echo -n resh \ && ( openaps monitor-pump || openaps monitor-pump ) 2>&1 >/dev/null | tail -1 \ && echo -n ed \ From 955bfbe25a9fbc21b0c438901386ff6bd61b1181 Mon Sep 17 00:00:00 2001 From: Scott Date: Thu, 24 Aug 2017 20:32:25 -0700 Subject: [PATCH 045/215] clarify bolus snooze reason (for #626) --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index e416a5b4f..94fa1a4ff 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -744,7 +744,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // if in SMB mode, don't cancel SMB zero temp if (! (microBolusAllowed && enableSMB )) { - rT.reason += convert_bg(eventualBG, profile)+"-"+convert_bg(Math.min(minPredBG,snoozeBG), profile)+" in range: no temp required"; + rT.reason += convert_bg(eventualBG, profile)+"-"+convert_bg(Math.min(minPredBG,snoozeBG), profile)+" in range: bolus snooze, no temp required"; if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) { rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. "; return rT; From 15f6a43ef0ea164c658eb62589a0cb0be7287337 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 27 Aug 2017 08:36:40 -0700 Subject: [PATCH 046/215] microBolus 1/2 the insulinReq if IOB doesn't yet cover COB (#621) * if IOB covers less than half of COB, microBolus 1/2 the insulinReq * syntax * logging cleanup * make SMB maxBolus configurable via maxSMBBasalMinutes * fix variable reference * fix variable reference * debugging * debugging * remove extra variable * debugging * fix math * still SMB 1/3 of insulinReq if that's more than halfMealInsulinReq * only allow more than 30m of basal as SMB when COB is uncovered * if IOB covers more than 3/4 of COB, limit maxBolus to 30m of basal * default to 30m if typeof profile_data.maxSMBBasalMinutes == 'undefined' * round mealInsulinReq * fix debug output * use insulinReq/2 up to 2/3 of COB, and maxSMBBasalMinutes up to 100% * allow SMBs every 2 minutes * microBolus 1/2 the insulinReq if IOB covers less than 3/4 of COB * if IOB doesn't cover COB, microBolus 1/2 the insulinReq --- lib/determine-basal/determine-basal.js | 31 +++++++++++++++++++++----- lib/iob/total.js | 15 ++++++++----- lib/profile/index.js | 1 + 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 94fa1a4ff..9ec5d9920 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -307,7 +307,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var totalCI = Math.max(0, ci / 5 * 60 * 4 / 2); // totalCI (mg/dL) / CSF (mg/dL/g) = total carbs absorbed (g) var totalCA = totalCI / csf; - // exclude the last 1/3 of carbs from remainingCarbs, and then cap it at 90 var remainingCarbsCap = 90; // default to 90 var remainingCarbsFraction = 1; if (profile.remainingCarbsCap) { remainingCarbsCap = Math.min(90,profile.remainingCarbsCap); } @@ -805,10 +804,30 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // only allow microboluses with COB or low temp targets, or within DIA hours of a bolus // only microbolus if 0.1U SMB represents 20m or less of basal (0.3U/hr or higher) if (microBolusAllowed && enableSMB && profile.current_basal >= 0.3 && bg > threshold) { - // never bolus more than 30m worth of basal - maxBolus = round(profile.current_basal/2,1); + // never bolus more than maxSMBBasalMinutes worth of basal + mealInsulinReq = round( meal_data.mealCOB / profile.carb_ratio ,3); + if (typeof profile.maxSMBBasalMinutes == 'undefined' ) { + maxBolus = round( profile.current_basal * 30 / 60 ,1); + console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m"); + // if IOB covers more than COB, limit maxBolus to 30m of basal + } else if (iob_data.iob > mealInsulinReq) { + console.error("IOB",iob_data.iob,"> COB",meal_data.mealCOB+"; mealInsulinReq =",mealInsulinReq); + maxBolus = round( profile.current_basal * 30 / 60 ,1); + } else { + console.error("profile.maxSMBBasalMinutes:",profile.maxSMBBasalMinutes,"profile.current_basal:",profile.current_basal); + maxBolus = round( profile.current_basal * profile.maxSMBBasalMinutes / 60 ,1); + } // bolus 1/3 the insulinReq, up to maxBolus microBolus = round(Math.min(insulinReq/3,maxBolus),1); + // if IOB doesn't cover COB, microBolus 1/2 the insulinReq + // (or enough insulin to cover COB, or maxBolus, whichever is smallest) + if ( iob_data.iob < mealInsulinReq ) { + initialMealInsulinReq = round(mealInsulinReq-iob_data.iob,1); + console.error("IOB",iob_data.iob,"<< COB",meal_data.mealCOB+"; insulinReq/2 =",insulinReq/2+"; initialMealInsulinReq =",initialMealInsulinReq); + if (initialMealInsulinReq > microBolus) { + microBolus = round(Math.min(insulinReq/2,maxBolus,initialMealInsulinReq),1); + } + } // calculate a long enough zero temp to eventually correct back up to target var smbTarget = target_bg; @@ -836,11 +855,11 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } rT.reason += ". "; - //allow SMBs every 3 minutes - var nextBolusMins = round(3-lastBolusAge,1); + //allow SMBs every 2 minutes + var nextBolusMins = round(2-lastBolusAge,1); //console.error(naive_eventualBG, insulinReq, worstCaseInsulinReq, durationReq); console.error("naive_eventualBG",naive_eventualBG+",",durationReq+"m zero temp needed; last bolus",lastBolusAge+"m ago; maxBolus: "+maxBolus); - if (lastBolusAge > 3) { + if (lastBolusAge > 2) { if (microBolus > 0) { rT.units = microBolus; rT.reason += "Microbolusing " + microBolus + "U. "; diff --git a/lib/iob/total.js b/lib/iob/total.js index 8226f28ca..763074227 100644 --- a/lib/iob/total.js +++ b/lib/iob/total.js @@ -30,12 +30,15 @@ function iobTotal(opts, time) { var tIOB = iobCalc(treatment, time, dia, profile_data); if (tIOB && tIOB.iobContrib) iob += tIOB.iobContrib; if (tIOB && tIOB.activityContrib) activity += tIOB.activityContrib; + if (typeof profile_data.maxSMBBasalMinutes == 'undefined' ) { + var maxSMB = profile_data.current_basal * 30 / 60; + //console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m"); + } else { + var maxSMB = profile_data.current_basal * 60 / profile_data.maxSMBBasalMinutes; + } // keep track of bolus IOB separately for snoozes, but decay it twice as fast - // only snooze for boluses that deliver more than 30m worth of basal (excludes SMBs) - //if (treatment.insulin && treatment.started_at) { - //console.error(treatment.insulin, treatment.started_at, profile_data.current_basal/1.5); - //} - if (treatment.insulin > profile_data.current_basal/1.5 && treatment.started_at) { + // only snooze for boluses that deliver more than maxSMBBasalMinutes m worth of basal (excludes SMBs) + if (treatment.insulin > maxSMB && treatment.started_at) { //default bolussnooze_dia_divisor is 2, for 2x speed bolus snooze // bIOB = bolus IOB if (tIOB.biobContrib !== undefined) { @@ -48,7 +51,7 @@ function iobTotal(opts, time) { } } else { // track microBolus IOB, but also count it toward basaliob and hightempinsulin - if (treatment.insulin <= profile_data.current_basal/1.5 && treatment.started_at) { + if (treatment.insulin <= maxSMB && treatment.started_at) { if(treatment.date > dia_ago && treatment.date <= now) { microBolusInsulin += treatment.insulin; } diff --git a/lib/profile/index.js b/lib/profile/index.js index 3d3a47f91..ee3d3b2b1 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -34,6 +34,7 @@ function defaults ( ) { , enableSMB_with_COB: false // enable supermicrobolus while COB is positive , enableSMB_with_temptarget: false // enable supermicrobolus for eating soon temp targets , enableSMB_after_carbs: false // enable supermicrobolus for 6h after carbs, even with 0 COB + , maxSMBBasalMinutes: 30 // maximum minutes of basal that can be delivered as a single SMB with uncovered COB , curve: "bilinear" , useCustomPeakTime: false , insulinPeakTime: 75 From 594a08594305edb086680d3ded880cedd302af8b Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 27 Aug 2017 08:36:56 -0700 Subject: [PATCH 047/215] model remainingCarbs as a /\ shaped bilinear curve (#620) * use profile.sens instead of autosens-adjusted sens * model remainingCarbs as a /\ shaped bilinear curve * typofix * wait 90m before setting minCOBPredBG * consider BG predictions out to 4h now * predict IOB out to 4h, regardless of DIA * limit cid to 4 hours: the reset goes to remainingCI * fix cid formula to end after 4h not 8h --- lib/determine-basal/determine-basal.js | 41 +++++++++++++++----------- lib/iob/index.js | 4 +-- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 9ec5d9920..4ff519a66 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -314,9 +314,12 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var remainingCarbsIgnore = 1 - remainingCarbsFraction; var remainingCarbs = Math.max(0, meal_data.mealCOB - totalCA - meal_data.carbs*remainingCarbsIgnore); remainingCarbs = Math.min(remainingCarbsCap,remainingCarbs); - // assume remainingCarbs will absorb over 4h + // assume remainingCarbs will absorb in a /\ shaped bilinear curve peaking at 2h and ending at 4h + // area of the /\ triangle is the same as a remainingCIpeak-height rectangle out to 2h + // remainingCIpeak (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / 2 (h) + var remainingCIpeak = remainingCarbs * csf * 5 / 60 / 2; // remainingCI (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / 4 (h) - var remainingCI = remainingCarbs * csf * 5 / 60 / 4; + //var remainingCI = remainingCarbs * csf * 5 / 60 / 4; //console.error(profile.min_5m_carbimpact,ci,totalCI,totalCA,remainingCarbs,remainingCI); //if (meal_data.mealCOB * 3 > meal_data.carbs) { } @@ -327,10 +330,11 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ aci = 10; //5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m) // duration (in 5m data points) = COB (g) * CSF (mg/dL/g) / ci (mg/dL/5m) - cid = Math.max(0, meal_data.mealCOB * csf / ci ); + // limit cid to 4 hours: the reset goes to remainingCI + cid = Math.min(4*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci )); acid = Math.max(0, meal_data.mealCOB * csf / aci ); // duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay) - console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining 4h+ CI:",round(remainingCI,1),"mg/dL per 5m"); + console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (2h peak):",round(remainingCIpeak,1),"mg/dL per 5m"); console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours"); var minIOBPredBG = 999; var minCOBPredBG = 999; @@ -360,10 +364,11 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // eventually accounting for all carbs (if they can be absorbed over DIA) predCI = Math.max(0, Math.max(0,ci) * ( 1 - COBpredBGs.length/Math.max(cid*2,1) ) ); predACI = Math.max(0, Math.max(0,aci) * ( 1 - COBpredBGs.length/Math.max(acid*2,1) ) ); - // if any carbs aren't absorbed after 4 hours, assume they'll absorb at a constant rate for next 4h + // if any carbs aren't absorbed after 4 hours, assume they'll absorb in a /\ shaped + // bilinear curve peaking at remainingCIpeak at 2h (24*5m) and ending at 4h (48*5m intervals) + var intervals = Math.min( COBpredBGs.length, 48-COBpredBGs.length ); + var remainingCI = Math.max(0, intervals / 24 * remainingCIpeak ); COBpredBG = COBpredBGs[COBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predCI + remainingCI; - // stop adding remainingCI after 4h - if (COBpredBGs.length > 4 * 60 / 5) { remainingCI = 0; } aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI; // for UAMpredBGs, predicted carb impact drops at minDeviationSlope // calculate predicted CI from UAM based on minDeviationSlope @@ -380,17 +385,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } UAMpredBG = UAMpredBGs[UAMpredBGs.length-1] + predBGI + Math.min(0, predDev) + predUCI; //console.error(predBGI, predCI, predUCI); - // truncate all BG predictions at 3.5 hours - if ( IOBpredBGs.length < 42) { IOBpredBGs.push(IOBpredBG); } - if ( COBpredBGs.length < 42) { COBpredBGs.push(COBpredBG); } - if ( aCOBpredBGs.length < 42) { aCOBpredBGs.push(aCOBpredBG); } - if ( UAMpredBGs.length < 42) { UAMpredBGs.push(UAMpredBG); } + // truncate all BG predictions at 4 hours + if ( IOBpredBGs.length < 48) { IOBpredBGs.push(IOBpredBG); } + if ( COBpredBGs.length < 48) { COBpredBGs.push(COBpredBG); } + if ( aCOBpredBGs.length < 48) { aCOBpredBGs.push(aCOBpredBG); } + if ( UAMpredBGs.length < 48) { UAMpredBGs.push(UAMpredBG); } // wait 90m before setting minIOBPredBG if ( IOBpredBGs.length > 18 && (IOBpredBG < minIOBPredBG) ) { minIOBPredBG = round(IOBpredBG); } if ( IOBpredBG > maxIOBPredBG ) { maxIOBPredBG = IOBpredBG; } - // wait 60m before setting COB and UAM minPredBGs - if ( (cid || remainingCI > 0) && COBpredBGs.length > 12 && (COBpredBG < minCOBPredBG) ) { minCOBPredBG = round(COBpredBG); } - if ( (cid || remainingCI > 0) && COBpredBG > maxIOBPredBG ) { maxCOBPredBG = COBpredBG; } + // wait 90m before setting COB and 60m for UAM minPredBGs + if ( (cid || remainingCIpeak > 0) && COBpredBGs.length > 18 && (COBpredBG < minCOBPredBG) ) { minCOBPredBG = round(COBpredBG); } + if ( (cid || remainingCIpeak > 0) && COBpredBG > maxIOBPredBG ) { maxCOBPredBG = COBpredBG; } if ( enableUAM && UAMpredBGs.length > 12 && (UAMpredBG < minUAMPredBG) ) { minUAMPredBG = round(UAMpredBG); } if ( enableUAM && UAMpredBG > maxIOBPredBG ) { maxUAMPredBG = UAMpredBG; } }); @@ -419,7 +424,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } rT.predBGs.aCOB = aCOBpredBGs; } - if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCI > 0 )) { + if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) { COBpredBGs.forEach(function(p, i, theArray) { theArray[i] = round(Math.min(401,Math.max(39,p))); }); @@ -431,7 +436,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ lastCOBpredBG=round(COBpredBGs[COBpredBGs.length-1]); eventualBG = Math.max(eventualBG, round(COBpredBGs[COBpredBGs.length-1]) ); } - if (ci > 0 || remainingCI > 0) { + if (ci > 0 || remainingCIpeak > 0) { if (enableUAM) { UAMpredBGs.forEach(function(p, i, theArray) { theArray[i] = round(Math.min(401,Math.max(39,p))); @@ -536,7 +541,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var bgUndershoot = target_bg - Math.max( naive_eventualBG, eventualBG, lastIOBpredBG ); // calculate how long until COB (or IOB) predBGs drop below min_bg var minutesAboveMinBG = 240; - if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCI > 0 )) { + if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) { for (var i=0; i Date: Mon, 28 Aug 2017 10:53:17 -0700 Subject: [PATCH 048/215] for purposes of categorizing boluses as SMBs to add to basalIOB, use max_daily_basal --- lib/iob/total.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/iob/total.js b/lib/iob/total.js index 763074227..8bf86d0d1 100644 --- a/lib/iob/total.js +++ b/lib/iob/total.js @@ -30,11 +30,12 @@ function iobTotal(opts, time) { var tIOB = iobCalc(treatment, time, dia, profile_data); if (tIOB && tIOB.iobContrib) iob += tIOB.iobContrib; if (tIOB && tIOB.activityContrib) activity += tIOB.activityContrib; + // for purposes of categorizing boluses as SMBs to add to basalIOB, use max_daily_basal if (typeof profile_data.maxSMBBasalMinutes == 'undefined' ) { - var maxSMB = profile_data.current_basal * 30 / 60; + var maxSMB = profile_data.max_daily_basal * 30 / 60; //console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m"); } else { - var maxSMB = profile_data.current_basal * 60 / profile_data.maxSMBBasalMinutes; + var maxSMB = profile_data.max_daily_basal * 60 / profile_data.maxSMBBasalMinutes; } // keep track of bolus IOB separately for snoozes, but decay it twice as fast // only snooze for boluses that deliver more than maxSMBBasalMinutes m worth of basal (excludes SMBs) From 1e331ec6ab8864e88215ac32a10e491e0e945135 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 2 Sep 2017 11:21:31 -0700 Subject: [PATCH 049/215] add max_daily_basal to fix tests --- tests/iob.test.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tests/iob.test.js b/tests/iob.test.js index 801e9cf62..657f013d7 100644 --- a/tests/iob.test.js +++ b/tests/iob.test.js @@ -28,7 +28,8 @@ describe('IOB', function() { dia: 3, bolussnooze_dia_divisor: 2, basalprofile: basalprofile, - current_basal: 1 + current_basal: 1, + max_daily_basal: 1 } }; @@ -77,6 +78,7 @@ describe('IOB', function() { bolussnooze_dia_divisor: 2, basalprofile: basalprofile, current_basal: 1, + max_daily_basal: 1, curve: 'ultra-rapid' } }; @@ -129,6 +131,7 @@ describe('IOB', function() { bolussnooze_dia_divisor: 2, basalprofile: basalprofile, current_basal: 1, + max_daily_basal: 1, curve: 'ultra-rapid' } }; @@ -179,6 +182,7 @@ describe('IOB', function() { bolussnooze_dia_divisor: 2, basalprofile: basalprofile, current_basal: 1, + max_daily_basal: 1, curve: 'ultra-rapid' } }; @@ -231,6 +235,7 @@ describe('IOB', function() { bolussnooze_dia_divisor: 2, basalprofile: basalprofile, current_basal: 1, + max_daily_basal: 1, curve: 'ultra-rapid' } }; @@ -284,6 +289,7 @@ describe('IOB', function() { bolussnooze_dia_divisor: 2, basalprofile: basalprofile, current_basal: 1, + max_daily_basal: 1, curve: 'ultra-rapid' } }; @@ -337,6 +343,7 @@ describe('IOB', function() { bolussnooze_dia_divisor: 2, basalprofile: basalprofile, current_basal: 1, + max_daily_basal: 1, curve: 'rapid-acting' } }; @@ -420,6 +427,7 @@ describe('IOB', function() { profile: { dia: 3, current_basal: 1, + max_daily_basal: 1, bolussnooze_dia_divisor: 2, 'basalprofile': basalprofile } @@ -538,6 +546,7 @@ describe('IOB', function() { profile: { dia: 3, current_basal: 0.1, + max_daily_basal: 1, bolussnooze_dia_divisor: 2, basalprofile: basalprofile } @@ -611,6 +620,7 @@ describe('IOB', function() { profile: { dia: 3, current_basal: 0.1, + max_daily_basal: 1, bolussnooze_dia_divisor: 2, basalprofile: basalprofile } @@ -672,6 +682,7 @@ describe('IOB', function() { profile: { dia: 3, current_basal: 0.1, + max_daily_basal: 1, bolussnooze_dia_divisor: 2, basalprofile: basalprofile } @@ -730,6 +741,7 @@ describe('IOB', function() { profile: { dia: 3, current_basal: 2, + max_daily_basal: 2, bolussnooze_dia_divisor: 2, 'basalprofile': basalprofile } @@ -776,6 +788,7 @@ describe('IOB', function() { profile: { dia: 3, current_basal: 1, + max_daily_basal: 1, 'basalprofile': basalprofile } }; @@ -825,6 +838,7 @@ describe('IOB', function() { profile: { dia: 3, current_basal: 2, + max_daily_basal: 2, bolussnooze_dia_divisor: 2, 'basalprofile': basalprofile } @@ -855,6 +869,7 @@ describe('IOB', function() { profile: { dia: 3, current_basal: 1, + max_daily_basal: 1, bolussnooze_dia_divisor: 2 } }; @@ -889,6 +904,7 @@ describe('IOB', function() { profile: { dia: 3, current_basal: 1, + max_daily_basal: 1, bolussnooze_dia_divisor: 2 } }; @@ -924,7 +940,8 @@ describe('IOB', function() { dia: 4, bolussnooze_dia_divisor: 2, basalprofile: basalprofile, - current_basal: 1 + current_basal: 1, + max_daily_basal: 1 } }; @@ -953,4 +970,4 @@ describe('IOB', function() { }); -}); \ No newline at end of file +}); From 384b514327b7af7476bd4672bfc90c16d24d9abd Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 2 Sep 2017 22:13:12 -0700 Subject: [PATCH 050/215] always mmtune on falure if mmtune.json is more than 15m old --- bin/oref0-pump-loop.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 40f714408..b4ad3f10e 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -348,11 +348,17 @@ function mmtune { } function maybe_mmtune { - # mmtune ~ 25% of the time - [[ $(( ( RANDOM % 100 ) )) > 75 ]] \ - && echo "Waiting for 30s silence before mmtuning" \ - && wait_for_silence 30 \ - && mmtune + if (find monitor/ -mmin +15 -size +5c | grep -q mmtune); then + echo "mmtune.json more than 15m old; waiting for 30s silence before mmtuning" + wait_for_silence 30 + mmtune + else + # mmtune ~ 25% of the time + [[ $(( ( RANDOM % 100 ) )) > 75 ]] \ + && echo "Waiting for 30s silence before mmtuning" \ + && wait_for_silence 30 \ + && mmtune + fi } # listen for $1 seconds of silence (no other rigs talking to pump) before continuing From 041b2231c10facd161eef6086701e744621a4202 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 2 Sep 2017 22:29:24 -0700 Subject: [PATCH 051/215] don't necessarily mmtune if pump_loop_completed within 15m --- bin/oref0-pump-loop.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index b4ad3f10e..5e9c335ba 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -348,16 +348,16 @@ function mmtune { } function maybe_mmtune { - if (find monitor/ -mmin +15 -size +5c | grep -q mmtune); then - echo "mmtune.json more than 15m old; waiting for 30s silence before mmtuning" - wait_for_silence 30 - mmtune - else + if ( find monitor/ -mmin -15 -size +5c | egrep -q "mmtune|pump_loop_completed" ); then # mmtune ~ 25% of the time [[ $(( ( RANDOM % 100 ) )) > 75 ]] \ && echo "Waiting for 30s silence before mmtuning" \ && wait_for_silence 30 \ && mmtune + else + echo "mmtune.json and pump_loop_completed more than 15m old; waiting for 30s silence before mmtuning" + wait_for_silence 30 + mmtune fi } From 04d7382b7b1159fc155409e09f4a23213f75fb2d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 3 Sep 2017 21:42:25 -0700 Subject: [PATCH 052/215] Always mmtune if pump_loop_completed > 15m old (#635) * pump_loop_completed is less than 5 bytes * syntax * always wait_for_silence and mmtune if pump_loop_completed > 15m old --- bin/oref0-pump-loop.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index a3b3b2f13..4e473cb52 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -350,14 +350,14 @@ function mmtune { } function maybe_mmtune { - if ( find monitor/ -mmin -15 -size +5c | egrep -q "mmtune|pump_loop_completed" ); then + if ( find monitor/ -mmin -15 | egrep -q "pump_loop_completed" ); then # mmtune ~ 25% of the time [[ $(( ( RANDOM % 100 ) )) > 75 ]] \ && echo "Waiting for 30s silence before mmtuning" \ && wait_for_silence 30 \ && mmtune else - echo "mmtune.json and pump_loop_completed more than 15m old; waiting for 30s silence before mmtuning" + echo "pump_loop_completed more than 15m old; waiting for 30s silence before mmtuning" wait_for_silence 30 mmtune fi From 3c970f198c5908580c1e00e38d29f6fcd660d79d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 4 Sep 2017 07:53:06 -0700 Subject: [PATCH 053/215] stop letting high temp run (#633) * stop letting high temp run * remove commented code --- lib/determine-basal/determine-basal.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 4ff519a66..060d5bf9b 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -740,12 +740,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } // eventualBG, snoozeBG, or minPredBG is below max_bg if (Math.min(eventualBG,snoozeBG,minPredBG) < max_bg) { - // if there is a high-temp running and eventualBG > max_bg, let it run - if (eventualBG > max_bg && round_basal(currenttemp.rate, profile) > round_basal(basal, profile) && currenttemp.duration > 5 ) { - rT.reason += eventualBG + " > " + max_bg + ": no temp required (letting high temp of " + currenttemp.rate + " run). " - return rT; - } - // if in SMB mode, don't cancel SMB zero temp if (! (microBolusAllowed && enableSMB )) { rT.reason += convert_bg(eventualBG, profile)+"-"+convert_bg(Math.min(minPredBG,snoozeBG), profile)+" in range: bolus snooze, no temp required"; From b60f34123eca201a066a11aa3420b02b43dfd6d7 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 4 Sep 2017 10:53:58 -0700 Subject: [PATCH 054/215] remove -g as it breaks autotune's time filters --- bin/ns-get.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/ns-get.sh b/bin/ns-get.sh index dc9b11efb..dddfd35ee 100755 --- a/bin/ns-get.sh +++ b/bin/ns-get.sh @@ -8,7 +8,7 @@ NIGHTSCOUT_HOST=${NIGHTSCOUT_HOST-${2-localhost:1337}} QUERY=${3} OUTPUT=${4-/dev/fd/1} -CURL_FLAGS="--compressed -g -s" +CURL_FLAGS="--compressed -s" NIGHTSCOUT_FORMAT=${NIGHTSCOUT_FORMAT-json} test "$NIGHTSCOUT_DEBUG" = "1" && CURL_FLAGS="${CURL_FLAGS} -iv" test "$NIGHTSCOUT_DEBUG" = "1" && set -x From 067ccacb8575e6fe5cfb4cb0af2d89aa7d166fc2 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 4 Sep 2017 11:25:17 -0700 Subject: [PATCH 055/215] Revert "remove -g as it breaks autotune's time filters" This reverts commit b60f34123eca201a066a11aa3420b02b43dfd6d7. --- bin/ns-get.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/ns-get.sh b/bin/ns-get.sh index dddfd35ee..dc9b11efb 100755 --- a/bin/ns-get.sh +++ b/bin/ns-get.sh @@ -8,7 +8,7 @@ NIGHTSCOUT_HOST=${NIGHTSCOUT_HOST-${2-localhost:1337}} QUERY=${3} OUTPUT=${4-/dev/fd/1} -CURL_FLAGS="--compressed -s" +CURL_FLAGS="--compressed -g -s" NIGHTSCOUT_FORMAT=${NIGHTSCOUT_FORMAT-json} test "$NIGHTSCOUT_DEBUG" = "1" && CURL_FLAGS="${CURL_FLAGS} -iv" test "$NIGHTSCOUT_DEBUG" = "1" && set -x From d3d3e524469a73d8bb0df8f8d159fc9d35b6d49a Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 5 Sep 2017 11:25:59 -0700 Subject: [PATCH 056/215] Allow nonzero low temps for SMB (#634) * pump_loop_completed is less than 5 bytes * syntax * always wait_for_silence and mmtune if pump_loop_completed > 15m old * set a nonzero low temp if SMB durationReq < 30m * debugging * logic fix * bugfix * Revert "logic fix" This reverts commit 168af3acf4dd0cf85d4a3bedcae72d11ac02ed68. * only smb_enact if no recent pump_loop_completed * syntax * debugging * recently = w/in 10m instead of 7m --- bin/oref0-pump-loop.sh | 11 +++++------ lib/determine-basal/determine-basal.js | 15 ++++++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 4e473cb52..94063ee0c 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -452,14 +452,13 @@ function refresh_old_profile { function refresh_smb_temp_and_enact { # set mtime of monitor/glucose.json to the time of its most recent glucose value setglucosetimestamp - if ( find monitor/ -newer monitor/pump_loop_completed | grep -q glucose.json ); then - echo "glucose.json newer than pump_loop_completed. " - smb_enact_temp - elif ( find monitor/ -mmin -5 -size +5c | grep -q monitor/pump_loop_completed ); then - echo "pump_loop_completed more than 5m ago. " + # only smb_enact_temp if we haven't successfully completed a pump_loop recently + # (no point in enacting a temp that's going to get changed after we see our last SMB) + if ( find monitor/ -mmin +10 | grep -q monitor/pump_loop_completed ); then + echo "pump_loop_completed more than 10m ago: setting temp before refreshing pumphistory. " smb_enact_temp else - echo -n "pump_loop_completed less than 5m ago. " + echo -n "pump_loop_completed less than 10m ago. " fi } diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 060d5bf9b..820b9c401 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -838,26 +838,31 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ durationReq = 0; } - if (durationReq < 0) { + var smbLowTempReq = 0; + if (durationReq <= 0) { durationReq = 0; // don't set a temp longer than 120 minutes - } else { + } else if (durationReq >= 30) { durationReq = round(durationReq/30)*30; durationReq = Math.min(120,Math.max(0,durationReq)); + } else { + // if SMB durationReq is less than 30m, set a nonzero low temp + smbLowTempReq = round( basal * durationReq/30 ,2); + durationReq = 30; } rT.reason += " insulinReq " + insulinReq; if (microBolus >= maxBolus) { rT.reason += "; maxBolus " + maxBolus; } if (durationReq > 0) { - rT.reason += "; setting " + durationReq + "m zero temp"; + rT.reason += "; setting " + durationReq + "m low temp of " + smbLowTempReq + "U/h"; } rT.reason += ". "; //allow SMBs every 2 minutes var nextBolusMins = round(2-lastBolusAge,1); //console.error(naive_eventualBG, insulinReq, worstCaseInsulinReq, durationReq); - console.error("naive_eventualBG",naive_eventualBG+",",durationReq+"m zero temp needed; last bolus",lastBolusAge+"m ago; maxBolus: "+maxBolus); + console.error("naive_eventualBG",naive_eventualBG+",",durationReq+"m "+smbLowTempReq+"U/h temp needed; last bolus",lastBolusAge+"m ago; maxBolus: "+maxBolus); if (lastBolusAge > 2) { if (microBolus > 0) { rT.units = microBolus; @@ -870,7 +875,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // if no zero temp is required, don't return yet; allow later code to set a high temp if (durationReq > 0) { - rT.rate = 0; + rT.rate = smbLowTempReq; rT.duration = durationReq; return rT; } From 8962fce8495b5bf3d20310f1174076e5f9bfd7a7 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 6 Sep 2017 17:24:36 -0700 Subject: [PATCH 057/215] don't allow maxSMBBasalMinutes > 30 unless IOB (and COB) are > 0 (#639) --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 820b9c401..d148d2038 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -809,7 +809,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ maxBolus = round( profile.current_basal * 30 / 60 ,1); console.error("profile.maxSMBBasalMinutes undefined: defaulting to 30m"); // if IOB covers more than COB, limit maxBolus to 30m of basal - } else if (iob_data.iob > mealInsulinReq) { + } else if ( iob_data.iob > mealInsulinReq && iob_data.iob > 0 ) { console.error("IOB",iob_data.iob,"> COB",meal_data.mealCOB+"; mealInsulinReq =",mealInsulinReq); maxBolus = round( profile.current_basal * 30 / 60 ,1); } else { From 52f4b30b8d8805e1ae42584edf8e4e10ae2e0cd5 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 6 Sep 2017 17:38:05 -0700 Subject: [PATCH 058/215] COB-aware autosens (#629) * remove unneeded stuff * reverse order to glucose_data to process oldest data first * exclude meal periods from autosens using autotune logic * add parentheses around meal periods * split cob-autosens into two separate files * split cob-autosens into two separate files * tag meal periods with carb amount or u(), and exclude avgDelta >= 6 * pull 24h+ carbhistory data for cob-aware-autosens * refresh pumphistory-24h more frequently now that autotune is faster * consider 60-70% Edison battery as charging * round COB for display * use carbhistory.json for autosens * use Math.round() not round() * don't use >24h-old carb treatments * don't interpolate missing data points for autosens * inputs.mealTime is only set in cob.js, not autosens.js * remove stuff that depends on mealTime * remove COB/UAM stuff that depends on ciTime * fix backwards logic * remove unused line * rename autosens main function * clean up autosens stuff from cob.js * fix to lastbgTime calc to properly bucket data from 2 receivers * only use last 8h worth of non-meal deviations for autosens * cleanup * remove bucketed_data[0] and properly filter meals before lastSiteChange --- bin/oref0-autotune.sh | 2 +- bin/oref0-detect-sensitivity.js | 21 +- bin/oref0-pump-loop.sh | 25 +- lib/autotune-prep/categorize.js | 7 - lib/determine-basal/autosens.js | 369 ++++++++++++++++++ .../{cob-autosens.js => cob.js} | 156 +------- lib/meal/total.js | 2 +- lib/oref0-setup/report.json | 4 +- 8 files changed, 404 insertions(+), 182 deletions(-) create mode 100644 lib/determine-basal/autosens.js rename lib/determine-basal/{cob-autosens.js => cob.js} (54%) diff --git a/bin/oref0-autotune.sh b/bin/oref0-autotune.sh index 57c911ecd..64a15e487 100755 --- a/bin/oref0-autotune.sh +++ b/bin/oref0-autotune.sh @@ -137,7 +137,7 @@ else exit 1 fi -# Get profile for testing copied to home directory. "openaps" is my loop directory name. +# Get profile for testing copied to home directory. cd $directory && mkdir -p autotune cp settings/pumpprofile.json autotune/profile.pump.json || die "Cannot copy settings/pumpprofile.json" # This allows manual users to be able to run autotune by simply creating a settings/pumpprofile.json file. diff --git a/bin/oref0-detect-sensitivity.js b/bin/oref0-detect-sensitivity.js index 41520d594..7d3a511d9 100755 --- a/bin/oref0-detect-sensitivity.js +++ b/bin/oref0-detect-sensitivity.js @@ -17,7 +17,7 @@ var basal = require('oref0/lib/profile/basal'); var get_iob = require('oref0/lib/iob'); -var detect = require('oref0/lib/determine-basal/cob-autosens'); +var detect = require('oref0/lib/determine-basal/autosens'); if (!module.parent) { var detectsensitivity = init(); @@ -27,9 +27,10 @@ if (!module.parent) { var isf_input = process.argv.slice(4, 5).pop() var basalprofile_input = process.argv.slice(5, 6).pop() var profile_input = process.argv.slice(6, 7).pop(); + var carb_input = process.argv.slice(7, 8).pop() if (!glucose_input || !pumphistory_input || !profile_input) { - console.error('usage: ', process.argv.slice(0, 2), ' '); + console.error('usage: ', process.argv.slice(0, 2), ' [carbhistory.json]'); process.exit(1); } @@ -62,6 +63,15 @@ if (!module.parent) { } var basalprofile = require(cwd + '/' + basalprofile_input); + var carb_data = { }; + if (typeof carb_input != 'undefined') { + try { + carb_data = JSON.parse(fs.readFileSync(carb_input, 'utf8')); + } catch (e) { + console.error("Warning: could not parse "+carb_input); + } + } + var iob_inputs = { history: pumphistory_data , profile: profile @@ -73,9 +83,10 @@ if (!module.parent) { var detection_inputs = { iob_inputs: iob_inputs - , glucose_data: glucose_data - , basalprofile: basalprofile - //, clock: clock_data + , carbs: carb_data + , glucose_data: glucose_data + , basalprofile: basalprofile + //, clock: clock_data }; detect(detection_inputs); var sensAdj = { diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 94063ee0c..d6b71afbe 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -494,19 +494,6 @@ function refresh_profile { || (echo -n Settings refresh && openaps get-settings 2>/dev/null >/dev/null && echo ed) } -function low_battery_wait { - if (! ls monitor/edison-battery.json 2>/dev/null >/dev/null); then - echo Edison battery level not found - elif (jq --exit-status ".battery >= 98 or (.battery <= 65 and .battery >= 60)" monitor/edison-battery.json > /dev/null); then - echo "Edison battery at $(jq .battery monitor/edison-battery.json)% is charged (>= 98%) or likely charging (60-65%)" - elif (jq --exit-status ".battery < 98" monitor/edison-battery.json > /dev/null); then - echo -n "Edison on battery: $(jq .battery monitor/edison-battery.json)%; " - wait_for_bg - else - echo Edison battery level unknown - fi -} - function wait_for_bg { if grep "MDT cgm" openaps.ini 2>&1 >/dev/null; then echo "MDT CGM configured; not waiting" @@ -530,16 +517,16 @@ function wait_for_bg { function refresh_pumphistory_24h { if (! ls monitor/edison-battery.json 2>/dev/null >/dev/null); then echo -n "Edison battery level not found. " - autosens_freq=20 - elif (jq --exit-status ".battery >= 98 or (.battery <= 65 and .battery >= 60)" monitor/edison-battery.json > /dev/null); then - echo -n "Edison battery at $(jq .battery monitor/edison-battery.json)% is charged (>= 98%) or likely charging (60-65%). " - autosens_freq=20 + autosens_freq=15 + elif (jq --exit-status ".battery >= 98 or (.battery <= 70 and .battery >= 60)" monitor/edison-battery.json > /dev/null); then + echo -n "Edison battery at $(jq .battery monitor/edison-battery.json)% is charged (>= 98%) or likely charging (60-70%). " + autosens_freq=15 elif (jq --exit-status ".battery < 98" monitor/edison-battery.json > /dev/null); then echo -n "Edison on battery: $(jq .battery monitor/edison-battery.json)%. " - autosens_freq=90 + autosens_freq=30 else echo -n "Edison battery level unknown. " - autosens_freq=20 + autosens_freq=15 fi find settings/ -mmin -$autosens_freq -size +100c | grep -q pumphistory-24h-zoned && echo "Pumphistory-24 < ${autosens_freq}m old" \ || (echo -n pumphistory-24h refresh \ diff --git a/lib/autotune-prep/categorize.js b/lib/autotune-prep/categorize.js index 98fea1119..91ac0995e 100644 --- a/lib/autotune-prep/categorize.js +++ b/lib/autotune-prep/categorize.js @@ -1,5 +1,4 @@ var tz = require('moment-timezone'); -//var calcMealCOB = require('oref0/lib/determine-basal/cob-autosens'); var basal = require('oref0/lib/profile/basal'); var getIOB = require('oref0/lib/iob'); var ISF = require('../profile/isf'); @@ -38,12 +37,6 @@ function categorizeBGDatums(opts) { profile: profileData , history: opts.pumpHistory }; - // TODO: verify this is safe to remove, and do so - var COBInputs = { - glucoseData: glucoseData - , IOBInputs: IOBInputs - , basalprofile: opts.basalprofile - }; var mealCOB = 0; var CSFGlucoseData = []; var ISFGlucoseData = []; diff --git a/lib/determine-basal/autosens.js b/lib/determine-basal/autosens.js new file mode 100644 index 000000000..38abf7cfd --- /dev/null +++ b/lib/determine-basal/autosens.js @@ -0,0 +1,369 @@ +var basal = require('oref0/lib/profile/basal'); +var get_iob = require('oref0/lib/iob'); +var find_insulin = require('oref0/lib/iob/history'); +var isf = require('../profile/isf'); +var find_meals = require('oref0/lib/meal/history'); +var tz = require('moment-timezone'); + +function detectSensitivity(inputs) { + + glucose_data = inputs.glucose_data.map(function prepGlucose (obj) { + //Support the NS sgv field to avoid having to convert in a custom way + obj.glucose = obj.glucose || obj.sgv; + return obj; + }); + iob_inputs = inputs.iob_inputs; + basalprofile = inputs.basalprofile; + profile = inputs.iob_inputs.profile; + + // use last 24h worth of data by default + var lastSiteChange = new Date(new Date().getTime() - (24 * 60 * 60 * 1000)); + if (inputs.iob_inputs.profile.rewind_resets_autosens ) { + // scan through pumphistory and set lastSiteChange to the time of the last pump rewind event + // if not present, leave lastSiteChange unchanged at 24h ago. + var history = inputs.iob_inputs.history; + for (var h=1; h < history.length; ++h) { + if ( ! history[h]._type || history[h]._type != "Rewind" ) { + //process.stderr.write("-"); + continue; + } + if ( history[h].timestamp ) { + lastSiteChange = new Date( history[h].timestamp ); + console.error("Setting lastSiteChange to",lastSiteChange,"using timestamp",history[h].timestamp); + break; + } + } + } + + // get treatments from pumphistory once, not every time we get_iob() + var treatments = find_insulin(inputs.iob_inputs); + + var mealinputs = { + history: inputs.iob_inputs.history + , profile: profile + , carbs: inputs.carbs + , glucose: inputs.glucose_data + //, prepped_glucose: prepped_glucose_data + }; + var meals = find_meals(mealinputs); + meals.sort(function (a, b) { + var aDate = new Date(tz(a.timestamp)); + var bDate = new Date(tz(b.timestamp)); + //console.error(aDate); + return bDate.getTime() - aDate.getTime(); + }); + //console.error(meals); + + var avgDeltas = []; + var bgis = []; + var deviations = []; + var deviationSum = 0; + var bucketed_data = []; + glucose_data.reverse(); + bucketed_data[0] = glucose_data[0]; + j=0; + // go through the meal treatments and remove any that are older than the oldest glucose value + //console.error(meals); + for (var i=1; i < glucose_data.length; ++i) { + var bgTime; + var lastbgTime; + if (glucose_data[i].display_time) { + bgTime = new Date(glucose_data[i].display_time.replace('T', ' ')); + } else if (glucose_data[i].dateString) { + bgTime = new Date(glucose_data[i].dateString); + } else { console.error("Could not determine BG time"); } + if (glucose_data[i-1].display_time) { + lastbgTime = new Date(glucose_data[i-1].display_time.replace('T', ' ')); + } else if (glucose_data[i-1].dateString) { + lastbgTime = new Date(glucose_data[i-1].dateString); + } else if (bucketed_data[0].display_time) { + lastbgTime = new Date(bucketed_data[0].display_time.replace('T', ' ')); + } else { console.error("Could not determine last BG time"); } + if (glucose_data[i].glucose < 39 || glucose_data[i-1].glucose < 39) { +//console.error("skipping:",glucose_data[i].glucose,glucose_data[i-1].glucose); + continue; + } + // only consider BGs since lastSiteChange + if (lastSiteChange) { + hoursSinceSiteChange = (bgTime-lastSiteChange)/(60*60*1000); + if (hoursSinceSiteChange < 0) { + //console.error(hoursSinceSiteChange, bgTime, lastSiteChange); + continue; + } + } + var elapsed_minutes = (bgTime - lastbgTime)/(60*1000); + if(Math.abs(elapsed_minutes) > 2) { + j++; + bucketed_data[j]=glucose_data[i]; + bucketed_data[j].date = bgTime.getTime(); + //console.error(elapsed_minutes, bucketed_data[j].glucose, glucose_data[i].glucose); + } else { + bucketed_data[j].glucose = (bucketed_data[j].glucose + glucose_data[i].glucose)/2; + //console.error(bucketed_data[j].glucose, glucose_data[i].glucose); + } + } + bucketed_data.shift(); + for (var i=meals.length-1; i>0; --i) { + var treatment = meals[i]; + //console.error(treatment); + if (treatment) { + var treatmentDate = new Date(tz(treatment.timestamp)); + var treatmentTime = treatmentDate.getTime(); + var glucoseDatum = bucketed_data[0]; + //console.error(glucoseDatum); + var BGDate = new Date(glucoseDatum.date); + var BGTime = BGDate.getTime(); + if ( treatmentTime < BGTime ) { + //console.error("Removing old meal: ",treatmentDate); + meals.splice(i,1); + } + } + } + var absorbing = 0; + var uam = 0; // unannounced meal + var mealCOB = 0; + var mealCarbs = 0; + var type=""; + //console.error(bucketed_data); + for (var i=3; i < bucketed_data.length; ++i) { + var bgTime = new Date(bucketed_data[i].date); + + var sens = isf.isfLookup(profile.isfProfile,bgTime); + + //console.error(bgTime , bucketed_data[i].glucose); + var bg; + var avgDelta; + var delta; + if (typeof(bucketed_data[i].glucose) != 'undefined') { + bg = bucketed_data[i].glucose; + if ( bg < 40 || bucketed_data[i-3].glucose < 40) { + process.stderr.write("!"); + continue; + } + avgDelta = (bg - bucketed_data[i-3].glucose)/3; + delta = (bg - bucketed_data[i-1].glucose); + } else { console.error("Could not find glucose data"); } + + avgDelta = avgDelta.toFixed(2); + iob_inputs.clock=bgTime; + iob_inputs.profile.current_basal = basal.basalLookup(basalprofile, bgTime); + //console.log(JSON.stringify(iob_inputs.profile)); + //console.error("Before: ", new Date().getTime()); + var iob = get_iob(iob_inputs, true, treatments)[0]; + //console.error("After: ", new Date().getTime()); + //console.log(JSON.stringify(iob)); + + var bgi = Math.round(( -iob.activity * sens * 5 )*100)/100; + bgi = bgi.toFixed(2); + //console.error(delta); + deviation = delta-bgi; + deviation = deviation.toFixed(2); + + var glucoseDatum = bucketed_data[i]; + //console.error(glucoseDatum); + var BGDate = new Date(glucoseDatum.date); + var BGTime = BGDate.getTime(); + // As we're processing each data point, go through the treatment.carbs and see if any of them are older than + // the current BG data point. If so, add those carbs to COB. + var treatment = meals[meals.length-1]; + if (treatment) { + var treatmentDate = new Date(tz(treatment.timestamp)); + var treatmentTime = treatmentDate.getTime(); + if ( treatmentTime < BGTime ) { + if (treatment.carbs >= 1) { + //console.error(treatmentDate, treatmentTime, BGTime, BGTime-treatmentTime); + mealCOB += parseFloat(treatment.carbs); + mealCarbs += parseFloat(treatment.carbs); + displayCOB = Math.round(mealCOB); + process.stderr.write(displayCOB.toString()); + } + meals.pop(); + } + } + + // calculate carb absorption for that 5m interval using the deviation. + if ( mealCOB > 0 ) { + //var profile = profileData; + ci = Math.max(deviation, profile.min_5m_carbimpact); + absorbed = ci * profile.carb_ratio / sens; + mealCOB = Math.max(0, mealCOB-absorbed); + } + // Store the COB, and use it as the starting point for the next data point. + + // If mealCOB is zero but all deviations since hitting COB=0 are positive, assign those data points to CSFGlucoseData + // Once deviations go negative for at least one data point after COB=0, we can use the rest of the data to tune ISF or basals + //console.error(mealCOB, absorbing, mealCarbs); + if (mealCOB > 0 || absorbing || mealCarbs > 0) { + if (deviation > 0) { + absorbing = 1; + } else { + absorbing = 0; + } + if ( ! absorbing && ! mealCOB ) { + mealCarbs = 0; + } + // check previous "type" value, and if it wasn't csf, set a mealAbsorption start flag + //console.error(type); + if ( type != "csf" ) { + process.stderr.write("g("); + //glucoseDatum.mealAbsorption = "start"; + //console.error(glucoseDatum.mealAbsorption,"carb absorption"); + } + type="csf"; + glucoseDatum.mealCarbs = mealCarbs; + //if (i == 0) { glucoseDatum.mealAbsorption = "end"; } + //CSFGlucoseData.push(glucoseDatum); + } else { + // check previous "type" value, and if it was csf, set a mealAbsorption end flag + if ( type === "csf" ) { + process.stderr.write(")"); + //CSFGlucoseData[CSFGlucoseData.length-1].mealAbsorption = "end"; + //console.error(CSFGlucoseData[CSFGlucoseData.length-1].mealAbsorption,"carb absorption"); + } + + currentBasal = iob_inputs.profile.current_basal; + if (iob.iob > currentBasal || uam) { + if (deviation > 0) { + uam = 1; + } else { + uam = 0; + } + if ( type != "uam" ) { + process.stderr.write("u("); + //glucoseDatum.uamAbsorption = "start"; + //console.error(glucoseDatum.uamAbsorption,"uannnounced meal absorption"); + } + type="uam"; + } else { + if ( type === "uam" ) { + process.stderr.write(")"); + //console.error("end unannounced meal absorption"); + } + type = "non-meal" + } + } + + // Exclude meal-related deviations (carb absorption) from autosens + if (type === "non-meal" && avgDelta-bgi < 6) { + if ( deviation > 0 ) { + //process.stderr.write(" "+bg.toString()); + process.stderr.write("+"); + } else if ( deviation == 0 ) { + process.stderr.write("="); + } else { + //process.stderr.write(" "+bg.toString()); + process.stderr.write("-"); + } + avgDeltas.push(avgDelta); + bgis.push(bgi); + deviations.push(deviation); + deviationSum += parseFloat(deviation); + } else { + process.stderr.write(">"); + //console.error(bgTime); + } + // only keep the last 96 non-excluded data points (8h+ for any exclusions) + if (deviations.length > 96) { + deviations.shift(); + } + } + //console.error(""); + process.stderr.write(" "); + //console.log(JSON.stringify(avgDeltas)); + //console.log(JSON.stringify(bgis)); + // when we have less than 8h worth of deviation data, add up to 1h of zero deviations + // this dampens any large sensitivity changes detected based on too little data, without ignoring them completely + console.error(""); + console.error("Using most recent",deviations.length,"deviations since",lastSiteChange); + if (deviations.length < 96) { + pad = Math.round((1 - deviations.length/96) * 12); + console.error("Adding",pad,"more zero deviations"); + for (var d=0; d 0.1; i = i - 0.02) { + //console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2)); + if ( percentile(deviations, (i+0.02)) >= 0 && percentile(deviations, i) < 0 ) { + //console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2)); + console.error(Math.round(100*i)+"% of non-meal deviations <= 0 (target 45%-50%)"); + } + } + pSensitive = percentile(deviations, 0.50); + pResistant = percentile(deviations, 0.45); + + average = deviationSum / deviations.length; + + //console.error("Mean deviation: "+average.toFixed(2)); + var basalOff = 0; + + if(pSensitive < 0) { // sensitive + basalOff = pSensitive * (60/5) / profile.sens; + process.stderr.write("Excess insulin sensitivity detected: "); + } else if (pResistant > 0) { // resistant + basalOff = pResistant * (60/5) / profile.sens; + process.stderr.write("Excess insulin resistance detected: "); + } else { + console.error("Sensitivity normal."); + } + ratio = 1 + (basalOff / profile.max_daily_basal); + + // don't adjust more than 1.2x by default (set in preferences.json) + var rawRatio = ratio; + ratio = Math.max(ratio, profile.autosens_min); + ratio = Math.min(ratio, profile.autosens_max); + + if (ratio !== rawRatio) { + console.error('Ratio limited from ' + rawRatio + ' to ' + ratio); + } + + ratio = Math.round(ratio*100)/100; + newisf = Math.round(profile.sens / ratio); + if (ratio != 1) { console.error("ISF adjusted from "+profile.sens+" to "+newisf); } + //console.error("Basal adjustment "+basalOff.toFixed(2)+"U/hr"); + //console.error("Ratio: "+ratio*100+"%: new ISF: "+newisf.toFixed(1)+"mg/dL/U"); + var output = { + "ratio": ratio + } + return output; +} +module.exports = detectSensitivity; + +// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2 +// Returns the value at a given percentile in a sorted numeric array. +// "Linear interpolation between closest ranks" method +function percentile(arr, p) { + if (arr.length === 0) return 0; + if (typeof p !== 'number') throw new TypeError('p must be a number'); + if (p <= 0) return arr[0]; + if (p >= 1) return arr[arr.length - 1]; + + var index = arr.length * p, + lower = Math.floor(index), + upper = lower + 1, + weight = index % 1; + + if (upper >= arr.length) return arr[lower]; + return arr[lower] * (1 - weight) + arr[upper] * weight; +} + +// Returns the percentile of the given value in a sorted numeric array. +function percentRank(arr, v) { + if (typeof v !== 'number') throw new TypeError('v must be a number'); + for (var i = 0, l = arr.length; i < l; i++) { + if (v <= arr[i]) { + while (i < l && v === arr[i]) i++; + if (i === 0) return 0; + if (v !== arr[i-1]) { + i += (v - arr[i-1]) / (arr[i] - arr[i-1]); + } + return i / l; + } + } + return 1; +} + diff --git a/lib/determine-basal/cob-autosens.js b/lib/determine-basal/cob.js similarity index 54% rename from lib/determine-basal/cob-autosens.js rename to lib/determine-basal/cob.js index 8d05e9a65..3eacceef1 100644 --- a/lib/determine-basal/cob-autosens.js +++ b/lib/determine-basal/cob.js @@ -3,7 +3,7 @@ var get_iob = require('oref0/lib/iob'); var find_insulin = require('oref0/lib/iob/history'); var isf = require('../profile/isf'); -function detectSensitivityandCarbAbsorption(inputs) { +function detectCarbAbsorption(inputs) { glucose_data = inputs.glucose_data.map(function prepGlucose (obj) { //Support the NS sgv field to avoid having to convert in a custom way @@ -18,25 +18,6 @@ function detectSensitivityandCarbAbsorption(inputs) { //console.error(mealTime, ciTime); - // use last 24h worth of data by default - var lastSiteChange = new Date(new Date().getTime() - (24 * 60 * 60 * 1000)); - if (inputs.iob_inputs.profile.rewind_resets_autosens && ! inputs.mealTime ) { - // scan through pumphistory and set lastSiteChange to the time of the last pump rewind event - // if not present, leave lastSiteChange unchanged at 24h ago. - var history = inputs.iob_inputs.history; - for (var h=1; h < history.length; ++h) { - if ( ! history[h]._type || history[h]._type != "Rewind" ) { - //process.stderr.write("-"); - continue; - } - if ( history[h].timestamp ) { - lastSiteChange = new Date( history[h].timestamp ); - console.error("Setting lastSiteChange to",lastSiteChange,"using timestamp",history[h].timestamp); - break; - } - } - } - // get treatments from pumphistory once, not every time we get_iob() var treatments = find_insulin(inputs.iob_inputs); @@ -69,16 +50,14 @@ function detectSensitivityandCarbAbsorption(inputs) { continue; } // only consider BGs for 6h after a meal for calculating COB - if (mealTime) { - hoursAfterMeal = (bgTime-mealTime)/(60*60*1000); - if (hoursAfterMeal > 6 || foundPreMealBG) { - continue; - } else if (hoursAfterMeal < 0) { + hoursAfterMeal = (bgTime-mealTime)/(60*60*1000); + if (hoursAfterMeal > 6 || foundPreMealBG) { + continue; + } else if (hoursAfterMeal < 0) { //console.error("Found pre-meal BG:",glucose_data[i].glucose, bgTime, Math.round(hoursAfterMeal*100)/100); - foundPreMealBG = true; - } -//console.error(glucose_data[i].glucose, bgTime, Math.round(hoursAfterMeal*100)/100, bucketed_data[bucketed_data.length-1].display_time); + foundPreMealBG = true; } +//console.error(glucose_data[i].glucose, bgTime, Math.round(hoursAfterMeal*100)/100, bucketed_data[bucketed_data.length-1].display_time); // only consider last hour of data in CI mode // this allows us to calculate deviations for the last ~45m if (typeof ciTime) { @@ -87,13 +66,6 @@ function detectSensitivityandCarbAbsorption(inputs) { continue; } } - // only consider BGs since lastSiteChange - if (lastSiteChange) { - hoursSinceSiteChange = (bgTime-lastSiteChange)/(60*60*1000); - if (hoursSinceSiteChange < 0) { - continue; - } - } var elapsed_minutes = (bgTime - lastbgTime)/(60*1000); //if (foundPreMealBG) { console.error(bgTime, lastbgTime, elapsed_minutes); } if(Math.abs(elapsed_minutes) > 8) { @@ -182,24 +154,6 @@ function detectSensitivityandCarbAbsorption(inputs) { //console.error("Deviations:",bgTime, avgDeviation, deviationSlope, minDeviationSlope); } - // Exclude large positive deviations (carb absorption) from autosens - if (avgDelta-bgi < 6) { - if ( deviation > 0 ) { - inputs.mealTime || process.stderr.write("+"); - } else if ( deviation == 0 ) { - inputs.mealTime || process.stderr.write("="); - } else { - inputs.mealTime || process.stderr.write("-"); - } - avgDeltas.push(avgDelta); - bgis.push(bgi); - deviations.push(deviation); - deviationSum += parseFloat(deviation); - } else { - inputs.mealTime || process.stderr.write(">"); - //console.error(bgTime); - } - // if bgTime is more recent than mealTime if(bgTime > mealTime) { // figure out how many carbs that represents @@ -214,105 +168,13 @@ function detectSensitivityandCarbAbsorption(inputs) { if(maxDeviation>0) { //console.error("currentDeviation:",currentDeviation,"maxDeviation:",maxDeviation,"minDeviationSlope:",minDeviationSlope); } - //console.error(""); - inputs.mealTime || process.stderr.write(" "); - //console.log(JSON.stringify(avgDeltas)); - //console.log(JSON.stringify(bgis)); - // when we have less than 12h worth of deviation data, add up to 1h of zero deviations - // this dampens any large sensitivity changes detected based on too little data, without ignoring them completely - if (! inputs.mealTime && deviations.length < 144) { - pad = Math.round((1 - deviations.length/144) * 12); - console.error("Found",deviations.length,"deviations since",lastSiteChange,"- adding",pad,"more zero deviations"); - for (var d=0; d 0.1; i = i - 0.02) { - //console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2)); - if ( percentile(deviations, (i+0.02)) >= 0 && percentile(deviations, i) < 0 ) { - //console.error("p="+i.toFixed(2)+": "+percentile(avgDeltas, i).toFixed(2)+", "+percentile(bgis, i).toFixed(2)+", "+percentile(deviations, i).toFixed(2)); - inputs.mealTime || console.error(Math.round(100*i)+"% of non-meal deviations <= 0 (target 45%-50%)"); - } - } - pSensitive = percentile(deviations, 0.50); - pResistant = percentile(deviations, 0.45); - - average = deviationSum / deviations.length; - - //console.error("Mean deviation: "+average.toFixed(2)); - var basalOff = 0; - - if(pSensitive < 0) { // sensitive - basalOff = pSensitive * (60/5) / profile.sens; - inputs.mealTime || process.stderr.write("Excess insulin sensitivity detected: "); - } else if (pResistant > 0) { // resistant - basalOff = pResistant * (60/5) / profile.sens; - inputs.mealTime || process.stderr.write("Excess insulin resistance detected: "); - } else { - inputs.mealTime || console.error("Sensitivity normal."); - } - ratio = 1 + (basalOff / profile.max_daily_basal); - - // don't adjust more than 1.2x by default (set in preferences.json) - var rawRatio = ratio; - ratio = Math.max(ratio, profile.autosens_min); - ratio = Math.min(ratio, profile.autosens_max); - if (ratio !== rawRatio) { - inputs.mealTime || console.error('Ratio limited from ' + rawRatio + ' to ' + ratio); - } - - ratio = Math.round(ratio*100)/100; - newisf = Math.round(profile.sens / ratio); - if (ratio != 1) { inputs.mealTime || console.error("ISF adjusted from "+profile.sens+" to "+newisf); } - //console.error("Basal adjustment "+basalOff.toFixed(2)+"U/hr"); - //console.error("Ratio: "+ratio*100+"%: new ISF: "+newisf.toFixed(1)+"mg/dL/U"); var output = { - "ratio": ratio - , "carbsAbsorbed": carbsAbsorbed + "carbsAbsorbed": carbsAbsorbed , "currentDeviation": currentDeviation , "maxDeviation": maxDeviation , "minDeviationSlope": minDeviationSlope } return output; } -module.exports = detectSensitivityandCarbAbsorption; - -// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2 -// Returns the value at a given percentile in a sorted numeric array. -// "Linear interpolation between closest ranks" method -function percentile(arr, p) { - if (arr.length === 0) return 0; - if (typeof p !== 'number') throw new TypeError('p must be a number'); - if (p <= 0) return arr[0]; - if (p >= 1) return arr[arr.length - 1]; - - var index = arr.length * p, - lower = Math.floor(index), - upper = lower + 1, - weight = index % 1; - - if (upper >= arr.length) return arr[lower]; - return arr[lower] * (1 - weight) + arr[upper] * weight; -} - -// Returns the percentile of the given value in a sorted numeric array. -function percentRank(arr, v) { - if (typeof v !== 'number') throw new TypeError('v must be a number'); - for (var i = 0, l = arr.length; i < l; i++) { - if (v <= arr[i]) { - while (i < l && v === arr[i]) i++; - if (i === 0) return 0; - if (v !== arr[i-1]) { - i += (v - arr[i-1]) / (arr[i] - arr[i-1]); - } - return i / l; - } - } - return 1; -} - +module.exports = detectCarbAbsorption; diff --git a/lib/meal/total.js b/lib/meal/total.js index 5f5c7d00a..2ea383572 100644 --- a/lib/meal/total.js +++ b/lib/meal/total.js @@ -1,5 +1,5 @@ var tz = require('moment-timezone'); -var calcMealCOB = require('oref0/lib/determine-basal/cob-autosens'); +var calcMealCOB = require('oref0/lib/determine-basal/cob'); function recentCarbs(opts, time) { var treatments = opts.treatments; diff --git a/lib/oref0-setup/report.json b/lib/oref0-setup/report.json index 38586c5c2..46913656d 100644 --- a/lib/oref0-setup/report.json +++ b/lib/oref0-setup/report.json @@ -18,7 +18,7 @@ "use": "shell", "reporter": "JSON", "device": "ns", - "remainder": "-18hours", + "remainder": "-36hours", "json_default": "True" }, "name": "monitor/carbhistory.json" @@ -244,7 +244,7 @@ "json_default": "True", "pumphistory": "settings/pumphistory-24h-zoned.json", "device": "detect-sensitivity", - "remainder": "", + "remainder": "monitor/carbhistory.json", "isf": "settings/insulin_sensitivities.json", "glucose": "monitor/glucose.json" }, From 6c2456f26b0e104bf4f08e12426bab6a8aead34f Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 6 Sep 2017 23:14:17 -0700 Subject: [PATCH 059/215] carbs: should only include carbs actually used in calculating COB (#640) * carbs: should only include carbs actually used in calculating COB * remove old unused mealAssist boluses field --- lib/meal/total.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/meal/total.js b/lib/meal/total.js index 2ea383572..b1596e21a 100644 --- a/lib/meal/total.js +++ b/lib/meal/total.js @@ -8,7 +8,6 @@ function recentCarbs(opts, time) { var glucose_data = opts.glucose; } var carbs = 0; - var boluses = 0; var carbDelay = 20 * 60 * 1000; var maxCarbs = 0; var mealCarbTime = time.getTime(); @@ -35,6 +34,7 @@ function recentCarbs(opts, time) { return bDate.getTime() - aDate.getTime(); }); + var carbsToRemove = 0; treatments.forEach(function(treatment) { var now = time.getTime(); // consider carbs from up to 6 hours ago in calculating COB @@ -49,13 +49,19 @@ function recentCarbs(opts, time) { var myCarbsAbsorbed = calcMealCOB(COB_inputs).carbsAbsorbed; var myMealCOB = Math.max(0, carbs - myCarbsAbsorbed); mealCOB = Math.max(mealCOB, myMealCOB); + //console.error(myMealCOB, mealCOB, carbs); + if (myMealCOB < mealCOB) { + carbsToRemove += parseFloat(treatment.carbs); + } else { + carbsToRemove = 0; + } + //console.error(carbs, carbsToRemove); //console.error("COB:",mealCOB); } - if (treatment.bolus >= 0.1) { - boluses += parseFloat(treatment.bolus); - } } }); + // only include carbs actually used in calculating COB + carbs -= carbsToRemove; // calculate the current deviation and steepest deviation downslope over the last hour COB_inputs.ciTime = time.getTime(); @@ -80,7 +86,6 @@ function recentCarbs(opts, time) { return { carbs: Math.round( carbs * 1000 ) / 1000 - , boluses: Math.round( boluses * 1000 ) / 1000 , mealCOB: Math.round( mealCOB ) , currentDeviation: Math.round( c.currentDeviation * 100 ) / 100 , maxDeviation: Math.round( c.maxDeviation * 100 ) / 100 From 9c89a54cdb3754bf390f28d361878819d0c9fb5c Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 6 Sep 2017 23:14:44 -0700 Subject: [PATCH 060/215] weight COBpredBG vs. UAMpredBG based on how many carbs remain as COB (#641) --- lib/determine-basal/determine-basal.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index d148d2038..5087a768b 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -461,9 +461,11 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ minUAMPredBG = Math.max(39,minUAMPredBG); minPredBG = round(minIOBPredBG); + var fractionCarbsLeft = meal_data.mealCOB/meal_data.carbs; // if we have COB and UAM is enabled, average all three if ( minUAMPredBG < 400 && minCOBPredBG < 400 ) { - avgPredBG = round( (IOBpredBG + UAMpredBG + COBpredBG)/3 ); + // weight COBpredBG vs. UAMpredBG based on how many carbs remain as COB + avgPredBG = round( (IOBpredBG/3 + (1-fractionCarbsLeft)*UAMpredBG*2/3 + fractionCarbsLeft*COBpredBG*2/3) ); // if UAM is disabled, average IOB and COB } else if ( minCOBPredBG < 400 ) { avgPredBG = round( (IOBpredBG + COBpredBG)/2 ); @@ -492,7 +494,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // if we have COB, use minCOBPredBG, or blendedMinPredBG if it's higher } else if ( minCOBPredBG < 400 ) { // calculate blendedMinPredBG based on how many carbs remain as COB - fractionCarbsLeft = meal_data.mealCOB/meal_data.carbs; blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*avgMinPredBG; // if blendedMinPredBG > minCOBPredBG, use that instead minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG, blendedMinPredBG)); From 8cfd6a73211985fd8cae0bd658cd351aaf497d4b Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 7 Sep 2017 10:06:42 -0700 Subject: [PATCH 061/215] Additional remainingCI debugging (#645) * use profile.sens instead of autosens-adjusted sens * model remainingCarbs as a /\ shaped bilinear curve * typofix * wait 90m before setting minCOBPredBG * if IOB covers less than half of COB, microBolus 1/2 the insulinReq * syntax * logging cleanup * consider BG predictions out to 4h now * make SMB maxBolus configurable via maxSMBBasalMinutes * fix variable reference * fix variable reference * debugging * debugging * remove extra variable * debugging * fix math * still SMB 1/3 of insulinReq if that's more than halfMealInsulinReq * only allow more than 30m of basal as SMB when COB is uncovered * if IOB covers more than 3/4 of COB, limit maxBolus to 30m of basal * if IOB covers more than 3/4 of COB, limit maxBolus to 30m of basal * default to 30m if typeof profile_data.maxSMBBasalMinutes == 'undefined' * default to 30m if typeof profile_data.maxSMBBasalMinutes == 'undefined' * round mealInsulinReq * fix debug output * ignore bolusing status if pump is suspended * use insulinReq/2 up to 2/3 of COB, and maxSMBBasalMinutes up to 100% * allow SMBs every 2 minutes * microBolus 1/2 the insulinReq if IOB covers less than 3/4 of COB * if IOB doesn't cover COB, microBolus 1/2 the insulinReq * debugging * debugging * debugging * predict IOB out to 4h, regardless of DIA * debugging * cid debugging * limit cid to 4 hours: the reset goes to remainingCI * remove extra debugging * remove extra debugging * cid debugging * fix cid formula to end after 4h not 8h * debugging * for purposes of categorizing boluses as SMBs to add to basalIOB, use max_daily_basal --- lib/determine-basal/determine-basal.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 5087a768b..ceb49c573 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -351,6 +351,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var lastCOBpredBG; var lastUAMpredBG; var UAMduration = 0; + var remainingCItotal = 0; + var remainingCIs = []; + var predCIs = []; try { iobArray.forEach(function(iobTick) { //console.error(iobTick); @@ -368,6 +371,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // bilinear curve peaking at remainingCIpeak at 2h (24*5m) and ending at 4h (48*5m intervals) var intervals = Math.min( COBpredBGs.length, 48-COBpredBGs.length ); var remainingCI = Math.max(0, intervals / 24 * remainingCIpeak ); + remainingCItotal += predCI+remainingCI; + remainingCIs.push(round(remainingCI,1)); + predCIs.push(round(predCI,1)); + //process.stderr.write(round(predCI,1)+"+"+round(remainingCI,1)+" "); COBpredBG = COBpredBGs[COBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predCI + remainingCI; aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI; // for UAMpredBGs, predicted carb impact drops at minDeviationSlope @@ -404,6 +411,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } catch (e) { console.error("Problem with iobArray. Optional feature Advanced Meal Assist disabled:",e); } + console.error("predCIs:",predCIs.join(" ")); + console.error("remainingCIs:",remainingCIs.join(" ")); + console.error("COB:",meal_data.mealCOB,"remainingCItotal/csf:",round(remainingCItotal/csf,2),"remainingCarbs:",round(remainingCarbs,2)); + //,"totalCA:",round(totalCA,2),"remainingCItotal/csf+totalCA:",round(remainingCItotal/csf+totalCA,2)); rT.predBGs = {}; IOBpredBGs.forEach(function(p, i, theArray) { theArray[i] = round(Math.min(401,Math.max(39,p))); From 4519a138c4e2753210bcbac56cf2d65e493099a5 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 7 Sep 2017 12:58:51 -0700 Subject: [PATCH 062/215] remove autosens avgDelta-bgi < 6 check (#643) * remove avgDelta-bgi < 6 check * use x for excluded now that we're not doing > 6 --- lib/determine-basal/autosens.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/determine-basal/autosens.js b/lib/determine-basal/autosens.js index 38abf7cfd..1dc1012f9 100644 --- a/lib/determine-basal/autosens.js +++ b/lib/determine-basal/autosens.js @@ -244,7 +244,7 @@ function detectSensitivity(inputs) { } // Exclude meal-related deviations (carb absorption) from autosens - if (type === "non-meal" && avgDelta-bgi < 6) { + if ( type === "non-meal" ) { if ( deviation > 0 ) { //process.stderr.write(" "+bg.toString()); process.stderr.write("+"); @@ -259,7 +259,7 @@ function detectSensitivity(inputs) { deviations.push(deviation); deviationSum += parseFloat(deviation); } else { - process.stderr.write(">"); + process.stderr.write("x"); //console.error(bgTime); } // only keep the last 96 non-excluded data points (8h+ for any exclusions) From 392f03220e9307d02414128cf9cef690c71f725a Mon Sep 17 00:00:00 2001 From: fidoman <26698840+efidoman@users.noreply.github.com> Date: Sat, 9 Sep 2017 20:47:43 -0400 Subject: [PATCH 063/215] Disable IPv6 for rig stability purposes (#649) --- bin/oref0-setup.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index cc3c6e914..99d57833b 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -829,7 +829,19 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then done touch /tmp/reboot-required fi - + + # disable IPv6 + if ! grep -q 'net.ipv6.conf.all.disable_ipv6=1' /etc/sysctl.conf; then + sudo echo 'net.ipv6.conf.all.disable_ipv6=1' >> /etc/sysctl.conf + fi + if ! grep -q 'net.ipv6.conf.default.disable_ipv6=1' /etc/sysctl.conf; then + sudo echo 'net.ipv6.conf.default.disable_ipv6=1' >> /etc/sysctl.conf + fi + if ! grep -q 'net.ipv6.conf.lo.disable_ipv6=1' /etc/sysctl.conf; then + sudo echo 'net.ipv6.conf.lo.disable_ipv6=1' >> /etc/sysctl.conf + fi + sudo sysctl -p + # Install EdisonVoltage if egrep -i "edison" /etc/passwd 2>/dev/null; then echo "Checking if EdisonVoltage is already installed" From 9e78f1001afa328c03cb0dd3d47aca9e0c94dc0e Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 10 Sep 2017 13:55:42 -0700 Subject: [PATCH 064/215] Autotune: calculate CR directly, and use CR*CSF to help calculate ISF (#644) Autotune: calculate CR directly --- bin/oref0-autotune-prep.js | 24 ++- bin/oref0-autotune-recommends-report.sh | 6 +- bin/oref0-autotune.sh | 129 ++++++------ bin/oref0-pump-loop.sh | 14 +- lib/autotune-prep/categorize.js | 143 +++++++++++-- lib/autotune-prep/dosed.js | 28 +++ lib/autotune-prep/index.js | 4 +- lib/autotune/index.js | 269 +++++++++++++++++------- 8 files changed, 437 insertions(+), 180 deletions(-) create mode 100644 lib/autotune-prep/dosed.js diff --git a/bin/oref0-autotune-prep.js b/bin/oref0-autotune-prep.js index 76cda757f..5b79c525a 100755 --- a/bin/oref0-autotune-prep.js +++ b/bin/oref0-autotune-prep.js @@ -22,7 +22,7 @@ var generate = require('oref0/lib/autotune-prep'); function usage ( ) { - console.error('usage: ', process.argv.slice(0, 2), ' [carbhistory.json] [autotune/glucose.json]'); + console.error('usage: ', process.argv.slice(0, 2), ' [pumpprofile.json] [carbhistory.json] [autotune/glucose.json]'); } if (!module.parent) { @@ -33,8 +33,9 @@ if (!module.parent) { } var profile_input = process.argv.slice(3, 4).pop(); var glucose_input = process.argv.slice(4, 5).pop(); - var carb_input = process.argv.slice(5, 6).pop() - var prepped_glucose_input = process.argv.slice(6, 7).pop() + var pumpprofile_input = process.argv.slice(5, 6).pop() + var carb_input = process.argv.slice(6, 7).pop() + var prepped_glucose_input = process.argv.slice(7, 8).pop() if ( !pumphistory_input || !profile_input || !glucose_input ) { usage( ); @@ -51,10 +52,23 @@ if (!module.parent) { return console.error("Could not parse input data: ", e); } + var pumpprofile_data = { }; + if (typeof pumpprofile_input != 'undefined') { + try { + pumpprofile_data = JSON.parse(fs.readFileSync(pumpprofile_input, 'utf8')); + } catch (e) { + console.error("Warning: could not parse "+pumpprofile_input); + } + } + // disallow impossibly low carbRatios due to bad decoding if ( typeof(profile_data.carb_ratio) == 'undefined' || profile_data.carb_ratio < 2 ) { - console.log('{ "carbs": 0, "mealCOB": 0, "reason": "carb_ratio ' + profile_data.carb_ratio + ' out of bounds" }'); - return console.error("Error: carb_ratio " + profile_data.carb_ratio + " out of bounds"); + if ( typeof(pumpprofile_data.carb_ratio) == 'undefined' || pumpprofile_data.carb_ratio < 2 ) { + console.log('{ "carbs": 0, "mealCOB": 0, "reason": "carb_ratios ' + profile_data.carb_ratio + ' and ' + pumpprofile_data.carb_ratio + ' out of bounds" }'); + return console.error("Error: carb_ratios " + profile_data.carb_ratio + ' and ' + pumpprofile_data.carb_ratio + " out of bounds"); + } else { + profile_data.carb_ratio = pumpprofile_data.carb_ratio; + } } try { diff --git a/bin/oref0-autotune-recommends-report.sh b/bin/oref0-autotune-recommends-report.sh index 09627cc43..2c0fb89c2 100755 --- a/bin/oref0-autotune-recommends-report.sh +++ b/bin/oref0-autotune-recommends-report.sh @@ -64,7 +64,7 @@ csf_new=$(cat $directory/autotune/profile.json | jq '.csf') carb_ratio_new=$(cat $directory/autotune/profile.json | jq '.carb_ratio') # Print Header Info -printf "%-${parameter_width}s| %-${data_width}s| %-${data_width}s\n" "Parameter" "Current" "Autotune" >> $report_file +printf "%-${parameter_width}s| %-${data_width}s| %-${data_width}s\n" "Parameter" "Pump" "Autotune" >> $report_file printf "%s\n" "-------------------------------------" >> $report_file # Print ISF, CSF and Carb Ratio Recommendations @@ -74,10 +74,10 @@ if [ $csf_current != null ]; then else printf "%-${parameter_width}s| %-${data_width}s| %-${data_width}.3f\n" "CSF [mg/dL/g]" "n/a" $csf_new >> $report_file fi -printf "%-${parameter_width}s| %-${data_width}.3f| %-${data_width}.3f\n" "Carb Ratio [g]" $carb_ratio_current $carb_ratio_new >> $report_file +printf "%-${parameter_width}s| %-${data_width}.3f| %-${data_width}.3f\n" "Carb Ratio[g/U]" $carb_ratio_current $carb_ratio_new >> $report_file # Print Basal Profile Recommendations -printf "%-${parameter_width}s| %-${data_width}s|\n" "Basal Profile [unit/hour]" "-" >> $report_file +printf "%-${parameter_width}s| %-${data_width}s|\n" "Basals [U/hr]" "-" >> $report_file # Build time_list array of H:M in 30 minute increments to mirror pump basal schedule time_list=() diff --git a/bin/oref0-autotune.sh b/bin/oref0-autotune.sh index 64a15e487..1b1ecac32 100755 --- a/bin/oref0-autotune.sh +++ b/bin/oref0-autotune.sh @@ -1,7 +1,7 @@ #!/bin/bash # This script sets up an easy test environment for autotune, allowing the user to vary parameters -# like start/end date and number of runs. +# like start/end date. # # Required Inputs: # DIR, (--dir=) @@ -10,8 +10,6 @@ # Optional Inputs: # END_DATE, (--end-date=) # if no end date supplied, assume we want a months worth or until day before current day -# NUMBER_OF_RUNS (--runs=) -# if no number of runs designated, then default to 5 # EXPORT_EXCEL (--xlsx=) # export to excel. Disabled by default # TERMINAL_LOGGING (--log @@ -39,7 +37,8 @@ DIR="" NIGHTSCOUT_HOST="" START_DATE="" END_DATE="" -NUMBER_OF_RUNS=1 # Default to a single run if not otherwise specified +START_DAYS_AGO=1 # Default to yesterday if not otherwise specified +END_DAYS_AGO=1 # Default to yesterday if not otherwise specified EXPORT_EXCEL="" # Default is to not export to Microsoft Excel TERMINAL_LOGGING=true RECOMMENDS_REPORT=true @@ -96,8 +95,12 @@ case $i in END_DATE=`date --date="$END_DATE" +%Y-%m-%d` shift # past argument=value ;; - -r=*|--runs=*) - NUMBER_OF_RUNS="${i#*=}" + -t=*|--start-days-ago=*) + START_DAYS_AGO="${i#*=}" + shift # past argument=value + ;; + -d=*|--end-days-ago=*) + END_DAYS_AGO="${i#*=}" shift # past argument=value ;; -x=*|--xlsx=*) @@ -116,22 +119,25 @@ case $i in esac done +# remove any trailing / from NIGHTSCOUT_HOST +NIGHTSCOUT_HOST=$(echo $NIGHTSCOUT_HOST | sed 's/\/$//g') + if [[ -z "$DIR" || -z "$NIGHTSCOUT_HOST" ]]; then - echo "Usage: oref0-autotune <--dir=myopenaps_directory> <--ns-host=https://mynightscout.azurewebsites.net> [--start-date=YYYY-MM-DD] [--end-date=YYYY-MM-DD] [--runs=number_of_runs] [--xlsx=autotune.xlsx] [--log=(true)|false]" + echo "Usage: oref0-autotune <--dir=myopenaps_directory> <--ns-host=https://mynightscout.azurewebsites.net> [--start-days-ago=number_of_days] [--end-days-ago=number_of_days] [--start-date=YYYY-MM-DD] [--end-date=YYYY-MM-DD] [--xlsx=autotune.xlsx] [--log=(true)|false]" exit 1 fi if [[ -z "$START_DATE" ]]; then # Default start date of yesterday - START_DATE=`date --date="1 day ago" +%Y-%m-%d` + START_DATE=`date --date="$START_DAYS_AGO days ago" +%Y-%m-%d` fi if [[ -z "$END_DATE" ]]; then # Default end-date as this morning at midnight in order to not get partial day samples for now # (ISF/CSF adjustments are still single values across each day) - END_DATE=`date --date="1 day ago" +%Y-%m-%d` + END_DATE=`date --date="$END_DAYS_AGO days ago" +%Y-%m-%d` fi if [[ -z "$UNKNOWN_OPTION" ]] ; then # everything is ok - echo "Running oref0-autotune --dir=$DIR --ns-host=$NIGHTSCOUT_HOST --start-date=$START_DATE --runs=$NUMBER_OF_RUNS --end-date=$END_DATE" + echo "Running oref0-autotune --dir=$DIR --ns-host=$NIGHTSCOUT_HOST --start-date=$START_DATE --end-date=$END_DATE" else echo "Unknown options. Exiting" exit 1 @@ -157,15 +163,6 @@ if [[ $TERMINAL_LOGGING = "true" ]]; then exec &> >(tee -a autotune.$(date +%Y-%m-%d-%H%M%S).log) fi -# Pull Nightscout Data -echo "Grabbing NIGHTSCOUT treatments.json for date range..." - -# Get Nightscout carb and insulin Treatments -query="find%5Bcreated_at%5D%5B%24gte%5D=`date --date="$START_DATE -4 hours" -Iminutes`&find%5Bcreated_at%5D%5B%24lte%5D=`date --date="$END_DATE +1 days" -Iminutes`" -echo Query: $NIGHTSCOUT_HOST/$query -ns-get host $NIGHTSCOUT_HOST treatments.json $query > ns-treatments.json || die "Couldn't download ns-treatments.json" -ls -la ns-treatments.json || die "No ns-treatments.json downloaded" - # Build date list for autotune iteration date_list=() date=$START_DATE; @@ -179,76 +176,74 @@ do fi done -echo "Grabbing NIGHTSCOUT entries/sgv.json for date range..." +echo "Grabbing NIGHTSCOUT treatments.json and entries/sgv.json for date range..." # Get Nightscout BG (sgv.json) Entries for i in "${date_list[@]}" do - query="find%5Bdate%5D%5B%24gte%5D=`(date -d $i +%s | tr -d '\n'; echo 000)`&find%5Bdate%5D%5B%24lte%5D=`(date --date="$i +1 days" +%s | tr -d '\n'; echo 000)`&count=1000" - echo Query: $NIGHTSCOUT_HOST $query - ns-get host $NIGHTSCOUT_HOST entries/sgv.json $query > ns-entries.$i.json || die "Couldn't download ns-entries.$i.json" - ls -la ns-entries.$i.json || die "No ns-entries.$i.json downloaded" -done - -echo "Running $NUMBER_OF_RUNS runs from $START_DATE to $END_DATE" -sleep 2 - -# Do iterative runs over date range, save autotune.json (prepped data) and input/output -# profile.json -# Loop 1: Run 1 to Number of Runs specified by user or by default (1) -for run_number in $(seq 1 $NUMBER_OF_RUNS) -do - # Loop 2: Iterate through Date Range - for i in "${date_list[@]}" - do - cp profile.json profile.$run_number.$i.json + query="find%5Bdate%5D%5B%24gte%5D=`(date -d $i +%s | tr -d '\n'; echo 000)`&find%5Bdate%5D%5B%24lte%5D=`(date --date="$i +1 days" +%s | tr -d '\n'; echo 000)`&count=1000" + echo Query: $NIGHTSCOUT_HOST $query + ns-get host $NIGHTSCOUT_HOST entries/sgv.json $query > ns-entries.$i.json || die "Couldn't download ns-entries.$i.json" + ls -la ns-entries.$i.json || die "No ns-entries.$i.json downloaded" + + # Get Nightscout carb and insulin Treatments + # echo $i $START_DATE; + #query="find%5Bdate%5D%5B%24gte%5D=`(date -d $i +%s | tr -d'\n'; echo 000)`&find%5Bdate%5D%5B%24lte%5D=`(date --date="$i +1 days" +%s | tr -d '\n'; echo 000)`&count=1000" + query="find%5Bcreated_at%5D%5B%24gte%5D=`date --date="$i -5 hours" -Iminutes`&find%5Bcreated_at%5D%5B%24lte%5D=`date --date="$i +1 days" -Iminutes`" + echo Query: $NIGHTSCOUT_HOST/$query + ns-get host $NIGHTSCOUT_HOST treatments.json $query > ns-treatments.$i.json || die "Couldn't download ns-treatments.$i.json" + ls -la ns-treatments.$i.json || die "No ns-treatments.$i.json downloaded" + + + # Do iterative runs over date range, save autotune.json (prepped data) and input/output profile.json + cp profile.json profile.$i.json # Autotune Prep (required args, ), output prepped glucose # data or below - echo "oref0-autotune-prep ns-treatments.json profile.json ns-entries.$i.json > autotune.$run_number.$i.json" - oref0-autotune-prep ns-treatments.json profile.json ns-entries.$i.json > autotune.$run_number.$i.json \ - || die "Could not run oref0-autotune-prep ns-treatments.json profile.json ns-entries.$i.json" + echo "oref0-autotune-prep ns-treatments.$i.json profile.json ns-entries.$i.json profile.pump.json > autotune.$i.json" + oref0-autotune-prep ns-treatments.$i.json profile.json ns-entries.$i.json profile.pump.json > autotune.$i.json \ + || die "Could not run oref0-autotune-prep ns-treatments.$i.json profile.json ns-entries.$i.json" # Autotune (required args, ), # output autotuned profile or what will be used as in the next iteration - echo "oref0-autotune-core autotune.$run_number.$i.json profile.json profile.pump.json > newprofile.$run_number.$i.json" - if ! oref0-autotune-core autotune.$run_number.$i.json profile.json profile.pump.json > newprofile.$run_number.$i.json; then + echo "oref0-autotune-core autotune.$i.json profile.json profile.pump.json > newprofile.$i.json" + if ! oref0-autotune-core autotune.$i.json profile.json profile.pump.json > newprofile.$i.json; then if cat profile.json | jq --exit-status .carb_ratio==null; then echo "ERROR: profile.json contains null carb_ratio: using profile.pump.json" cp profile.pump.json profile.json exit else - die "Could not run oref0-autotune-core autotune.$run_number.$i.json profile.json profile.pump.json" + die "Could not run oref0-autotune-core autotune.$i.json profile.json profile.pump.json" fi else # Copy tuned profile produced by autotune to profile.json for use with next day of data - cp newprofile.$run_number.$i.json profile.json + cp newprofile.$i.json profile.json fi - done # End Date Range Iteration -done # End Number of Runs Loop -if ! [[ -z "$EXPORT_EXCEL" ]]; then - echo Exporting to $EXPORT_EXCEL - oref0-autotune-export-to-xlsx --dir $DIR --output $EXPORT_EXCEL -fi + if ! [[ -z "$EXPORT_EXCEL" ]]; then + echo Exporting to $EXPORT_EXCEL + oref0-autotune-export-to-xlsx --dir $DIR --output $EXPORT_EXCEL + fi -# Create Summary Report of Autotune Recommendations and display in the terminal -if [[ $RECOMMENDS_REPORT == "true" ]]; then - # Set the report file name, so we can let the user know where it is and cat - # it to the screen - report_file=$directory/autotune/autotune_recommendations.log + # Create Summary Report of Autotune Recommendations and display in the terminal + if [[ $RECOMMENDS_REPORT == "true" ]]; then + # Set the report file name, so we can let the user know where it is and cat + # it to the screen + report_file=$directory/autotune/autotune_recommendations.log - echo - echo "Autotune pump profile recommendations:" - echo "---------------------------------------------------------" + echo + echo "Autotune pump profile recommendations:" + echo "---------------------------------------------------------" - # Let the user know where the Autotune Recommendations are logged - echo "Recommendations Log File: $report_file" - echo + # Let the user know where the Autotune Recommendations are logged + echo "Recommendations Log File: $report_file" + echo - # Run the Autotune Recommends Report - oref0-autotune-recommends-report $directory + # Run the Autotune Recommends Report + oref0-autotune-recommends-report $directory - # Go ahead and echo autotune_recommendations.log to the terminal, minus blank lines - cat $report_file | egrep -v "\| *\| *$" -fi + # Go ahead and echo autotune_recommendations.log to the terminal, minus blank lines + cat $report_file | egrep -v "\| *\| *$" + fi + +done # End Date Range Iteration diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index d6b71afbe..0628426b8 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -330,10 +330,10 @@ function mmtune { reset_spi_serial.py 2>/dev/null fi oref0_init_pump_comms.py - echo -n "Listening for 30s silence before mmtuning: " + echo -n "Listening for 40s silence before mmtuning: " for i in $(seq 1 800); do echo -n . - any_pump_comms 30 2>/dev/null | egrep -v subg | egrep No \ + any_pump_comms 40 2>/dev/null | egrep -v subg | egrep No \ && break done echo {} > monitor/mmtune.json @@ -353,12 +353,12 @@ function maybe_mmtune { if ( find monitor/ -mmin -15 | egrep -q "pump_loop_completed" ); then # mmtune ~ 25% of the time [[ $(( ( RANDOM % 100 ) )) > 75 ]] \ - && echo "Waiting for 30s silence before mmtuning" \ - && wait_for_silence 30 \ + && echo "Waiting for 40s silence before mmtuning" \ + && wait_for_silence 40 \ && mmtune else - echo "pump_loop_completed more than 15m old; waiting for 30s silence before mmtuning" - wait_for_silence 30 + echo "pump_loop_completed more than 15m old; waiting for 40s silence before mmtuning" + wait_for_silence 40 mmtune fi } @@ -370,7 +370,7 @@ function any_pump_comms { # listen for $1 seconds of silence (no other rigs talking to pump) before continuing function wait_for_silence { if [ -z $1 ]; then - waitfor=30 + waitfor=40 else waitfor=$1 fi diff --git a/lib/autotune-prep/categorize.js b/lib/autotune-prep/categorize.js index 91ac0995e..378301f9a 100644 --- a/lib/autotune-prep/categorize.js +++ b/lib/autotune-prep/categorize.js @@ -2,6 +2,8 @@ var tz = require('moment-timezone'); var basal = require('oref0/lib/profile/basal'); var getIOB = require('oref0/lib/iob'); var ISF = require('../profile/isf'); +var find_insulin = require('oref0/lib/iob/history'); +var dosed = require('./dosed'); // main function categorizeBGDatums. ;) categorize to ISF, CSF, or basals. @@ -37,10 +39,11 @@ function categorizeBGDatums(opts) { profile: profileData , history: opts.pumpHistory }; - var mealCOB = 0; var CSFGlucoseData = []; var ISFGlucoseData = []; var basalGlucoseData = []; + var UAMGlucoseData = []; + var CRData = []; var bucketedData = []; bucketedData[0] = glucoseData[0]; @@ -96,10 +99,12 @@ function categorizeBGDatums(opts) { } } //console.error(treatments); - absorbing = 0; - uam = 0; // unannounced meal - mealCOB = 0; - mealCarbs = 0; + var calculatingCR = false; + var absorbing = 0; + var uam = 0; // unannounced meal + var mealCOB = 0; + var mealCarbs = 0; + var CRCarbs = 0; var type=""; // main for loop for (var i=bucketedData.length-5; i > 0; --i) { @@ -110,6 +115,7 @@ function categorizeBGDatums(opts) { // As we're processing each data point, go through the treatment.carbs and see if any of them are older than // the current BG data point. If so, add those carbs to COB. var treatment = treatments[treatments.length-1]; + var myCarbs = 0; if (treatment) { var treatmentDate = new Date(tz(treatment.timestamp)); var treatmentTime = treatmentDate.getTime(); @@ -118,6 +124,7 @@ function categorizeBGDatums(opts) { if (treatment.carbs >= 1) { mealCOB += parseFloat(treatment.carbs); mealCarbs += parseFloat(treatment.carbs); + myCarbs = treatment.carbs; } treatments.pop(); } @@ -141,12 +148,12 @@ function categorizeBGDatums(opts) { avgDelta = avgDelta.toFixed(2); glucoseDatum.avgDelta = avgDelta; - + //sens = ISF var sens = ISF.isfLookup(IOBInputs.profile.isfProfile,BGDate); IOBInputs.clock=BGDate.toISOString(); - // use the average of the last 4 hours' basals to help convergence; - // this helps since the basal this hour could be different from previous, especially if with autotune they start to diverge. + // use the average of the last 4 hours' basals to help convergence; + // this helps since the basal this hour could be different from previous, especially if with autotune they start to diverge. currentBasal = basal.basalLookup(opts.basalprofile, BGDate); BGDate1hAgo = new Date(BGTime-1*60*60*1000); BGDate2hAgo = new Date(BGTime-2*60*60*1000); @@ -159,7 +166,7 @@ function categorizeBGDatums(opts) { //console.error(currentBasal,basal1hAgo,basal2hAgo,basal3hAgo,IOBInputs.profile.currentBasal); // basalBGI is BGI of basal insulin activity. - basalBGI = Math.round(( currentBasal * sens / 60 * 5 )*100)/100; // U/hr * mg/dL/U * 1 hr / 60 minutes * 5 = mg/dL/5m + basalBGI = Math.round(( currentBasal * sens / 60 * 5 )*100)/100; // U/hr * mg/dL/U * 1 hr / 60 minutes * 5 = mg/dL/5m //console.log(JSON.stringify(IOBInputs.profile)); // call iob since calculated elsewhere var iob = getIOB(IOBInputs)[0]; @@ -182,14 +189,70 @@ function categorizeBGDatums(opts) { var profile = profileData; ci = Math.max(deviation, profile.min_5m_carbimpact); absorbed = ci * profile.carb_ratio / sens; + // Store the COB, and use it as the starting point for the next data point. mealCOB = Math.max(0, mealCOB-absorbed); } - // Store the COB, and use it as the starting point for the next data point. + + + // Calculate carb ratio (CR) independently of CSF and ISF + // Use the time period from meal bolus/carbs until COB is zero and IOB is < currentBasal/2 + // For now, if another meal IOB/COB stacks on top of it, consider them together + // Compare beginning and ending BGs, and calculate how much more/less insulin is needed to neutralize + // Use entered carbs vs. starting IOB + delivered insulin + needed-at-end insulin to directly calculate CR. + + if (mealCOB > 0 || calculatingCR ) { + // set initial values when we first see COB + CRCarbs += myCarbs; + if (!calculatingCR) { + CRInitialIOB = iob.iob; + CRInitialBG = glucoseDatum.glucose; + CRInitialCarbTime = new Date(glucoseDatum.date); + console.error("CRInitialIOB:",CRInitialIOB,"CRInitialBG:",CRInitialBG,"CRInitialCarbTime:",CRInitialCarbTime); + } + // keep calculatingCR as long as we have COB or enough IOB + if ( mealCOB > 0 && i>1 ) { + calculatingCR = true; + } else if ( iob.iob > currentBasal/2 && i>1 ) { + calculatingCR = true; + // when COB=0 and IOB drops low enough, record end values and be done calculatingCR + } else { + CREndIOB = iob.iob; + CREndBG = glucoseDatum.glucose; + CREndTime = new Date(glucoseDatum.date); + console.error("CREndIOB:",CREndIOB,"CREndBG:",CREndBG,"CREndTime:",CREndTime); + var CRDatum = { + CRInitialIOB: CRInitialIOB + , CRInitialBG: CRInitialBG + , CRInitialCarbTime: CRInitialCarbTime + , CREndIOB: CREndIOB + , CREndBG: CREndBG + , CREndTime: CREndTime + , CRCarbs: CRCarbs + }; + //console.error(CRDatum); + + var CRElapsedMinutes = Math.round((CREndTime - CRInitialCarbTime) / 1000 / 60); + //console.error(CREndTime - CRInitialCarbTime, CRElapsedMinutes); + if ( CRElapsedMinutes < 60 ) { + console.error("Ignoring",CRElapsedMinutes,"m CR period."); + } else { + CRData.push(CRDatum); + } + + CRCarbs = 0; + calculatingCR = false; + } + } + // If mealCOB is zero but all deviations since hitting COB=0 are positive, assign those data points to CSFGlucoseData // Once deviations go negative for at least one data point after COB=0, we can use the rest of the data to tune ISF or basals if (mealCOB > 0 || absorbing || mealCarbs > 0) { - if (deviation > 0) { + // if meal IOB has decayed, then end absorption after this data point unless COB > 0 + if ( iob.iob < currentBasal/2 ) { + absorbing = 0; + // otherwise, as long as deviations are positive, keep tracking carb deviations + } else if (deviation > 0) { absorbing = 1; } else { absorbing = 0; @@ -214,7 +277,8 @@ function categorizeBGDatums(opts) { console.error(CSFGlucoseData[CSFGlucoseData.length-1].mealAbsorption,"carb absorption"); } - if (iob.iob > currentBasal || uam) { + // check that we have a decent amount of basal tuning data before excluding data as UAM + if ((iob.iob > currentBasal || uam) ) { if (deviation > 0) { uam = 1; } else { @@ -225,6 +289,7 @@ function categorizeBGDatums(opts) { console.error(glucoseDatum.uamAbsorption,"uannnounced meal absorption"); } type="uam"; + UAMGlucoseData.push(glucoseDatum); } else { if ( type === "uam" ) { console.error("end unannounced meal absorption"); @@ -240,12 +305,12 @@ function categorizeBGDatums(opts) { // attempting to prevent basal from being calculated as negative; should help prevent basals from going below 0 var minPossibleDeviation = -( basalBGI + Math.max(0,BGI) ); //var minPossibleDeviation = -basalBGI; - if ( deviation < minPossibleDeviation ) { - console.error("Adjusting deviation",deviation,"to",minPossibleDeviation.toFixed(2)); - deviation = minPossibleDeviation; - deviation = deviation.toFixed(2); - glucoseDatum.deviation = deviation; - } + //if ( deviation < minPossibleDeviation ) { + //console.error("Adjusting deviation",deviation,"to",minPossibleDeviation.toFixed(2)); + //deviation = minPossibleDeviation; + //deviation = deviation.toFixed(2); + //glucoseDatum.deviation = deviation; + //} type="basal"; basalGlucoseData.push(glucoseDatum); } else { @@ -266,7 +331,49 @@ function categorizeBGDatums(opts) { console.error(absorbing.toString(),"mealCOB:",mealCOB.toFixed(1),"mealCarbs:",mealCarbs,"basalBGI:",basalBGI.toFixed(1),"BGI:",BGI.toFixed(1),"IOB:",iob.iob.toFixed(1),"at",BGTime,"dev:",deviation,"avgDelta:",avgDelta,type); } + var IOBInputs = { + profile: profileData + , history: opts.pumpHistory + }; + var treatments = find_insulin(IOBInputs); + CRData.forEach(function(CRDatum) { + var dosedOpts = { + treatments: treatments + , profile: opts.profile + , start: CRDatum.CRInitialCarbTime + , end: CRDatum.CREndTime + }; + var insulinDosed = dosed(dosedOpts); + CRDatum.CRInsulin = insulinDosed.insulin; + //console.error(CRDatum); + }); + + var CSFLength = CSFGlucoseData.length; + var ISFLength = ISFGlucoseData.length; + var UAMLength = UAMGlucoseData.length; + var basalLength = basalGlucoseData.length; + + if (4*basalLength < CSFLength) { + console.error("Warning: too many deviations categorized as meals"); + //console.error("Adding",CSFLength,"CSF deviations to",basalLength,"basal ones"); + //var basalGlucoseData = basalGlucoseData.concat(CSFGlucoseData); + console.error("Adding",CSFLength,"CSF deviations to",ISFLength,"ISF ones"); + var ISFGlucoseData = ISFGlucoseData.concat(CSFGlucoseData); + CSFGlucoseData = []; + } + + if (2*basalLength < UAMLength) { + //console.error(basalGlucoseData, UAMGlucoseData); + console.error("Warning: too many deviations categorized as UnAnnounced Meals"); + console.error("Adding",UAMLength,"UAM deviations to",basalLength,"basal ones"); + var basalGlucoseData = basalGlucoseData.concat(UAMGlucoseData); + console.error("Adding",UAMLength,"UAM deviations to",ISFLength,"ISF ones"); + var ISFGlucoseData = ISFGlucoseData.concat(UAMGlucoseData); + //console.error(ISFGlucoseData.length, UAMLength); + } + return { + CRData: CRData, CSFGlucoseData: CSFGlucoseData, ISFGlucoseData: ISFGlucoseData, basalGlucoseData: basalGlucoseData diff --git a/lib/autotune-prep/dosed.js b/lib/autotune-prep/dosed.js new file mode 100644 index 000000000..41c207ab3 --- /dev/null +++ b/lib/autotune-prep/dosed.js @@ -0,0 +1,28 @@ +function insulinDosed(opts) { + + var start = opts.start.getTime(); + var end = opts.end.getTime(); + var treatments = opts.treatments; + var profile_data = opts.profile; + var insulinDosed = 0; + if (!treatments) { + console.error("No treatments to process."); + return {}; + } + + treatments.forEach(function(treatment) { + //console.error(treatment); + if(treatment.insulin && treatment.date > start && treatment.date <= end) { + insulinDosed += treatment.insulin; + } + }); + //console.error(insulinDosed); + + var rval = { + insulin: Math.round( insulinDosed * 1000 ) / 1000 + }; + + return rval; +} + +exports = module.exports = insulinDosed; diff --git a/lib/autotune-prep/index.js b/lib/autotune-prep/index.js index 0afa3dde9..971610468 100644 --- a/lib/autotune-prep/index.js +++ b/lib/autotune-prep/index.js @@ -3,7 +3,7 @@ var tz = require('moment-timezone'); var find_meals = require('oref0/lib/meal/history'); -var sum = require('./categorize'); +var categorize = require('./categorize'); function generate (inputs) { @@ -19,7 +19,7 @@ function generate (inputs) { , basalprofile: inputs.profile.basalprofile }; - var autotune_prep_output = sum(opts); + var autotune_prep_output = categorize(opts); return autotune_prep_output; } diff --git a/lib/autotune/index.js b/lib/autotune/index.js index 10739dbcd..b29f2e588 100644 --- a/lib/autotune/index.js +++ b/lib/autotune/index.js @@ -23,6 +23,9 @@ function tuneAllTheThings (inputs) { pumpCarbRatio = pumpProfile.carb_ratio; pumpCSF = pumpISF / pumpCarbRatio; } + if (! carbRatio) { carbRatio = pumpCarbRatio; } + if (! CSF) { CSF = pumpCSF; } + if (! ISF) { ISF = pumpISF; } //console.error(CSF); var preppedGlucose = inputs.preppedGlucose; var CSFGlucose = preppedGlucose.CSFGlucoseData; @@ -31,12 +34,40 @@ function tuneAllTheThings (inputs) { //console.error(ISFGlucose[0]); var basalGlucose = preppedGlucose.basalGlucoseData; //console.error(basalGlucose[0]); + var CRData = preppedGlucose.CRData; + //console.error(CRData); + + // Calculate carb ratio (CR) independently of CSF and ISF + // Use the time period from meal bolus/carbs until COB is zero and IOB is < currentBasal/2 + // For now, if another meal IOB/COB stacks on top of it, consider them together + // Compare beginning and ending BGs, and calculate how much more/less insulin is needed to neutralize + // Use entered carbs vs. starting IOB + delivered insulin + needed-at-end insulin to directly calculate CR. + + var CRTotalCarbs = 0; + var CRTotalInsulin = 0; + CRData.forEach(function(CRDatum) { + CRBGChange = CRDatum.CREndBG - CRDatum.CRInitialBG; + CRInsulinReq = CRBGChange / ISF; + CRIOBChange = CRDatum.CREndIOB - CRDatum.CRInitialIOB; + CRDatum.CRInsulinTotal = CRDatum.CRInitialIOB + CRDatum.CRInsulin + CRInsulinReq; + //console.error(CRDatum.CRInitialIOB, CRDatum.CRInsulin, CRInsulinReq, CRInsulinTotal); + CR = Math.round( CRDatum.CRCarbs / CRDatum.CRInsulinTotal * 1000 )/1000; + //console.error(CRBGChange, CRInsulinReq, CRIOBChange, CRInsulinTotal); + //console.error("CRCarbs:",CRDatum.CRCarbs,"CRInsulin:",CRDatum.CRInsulinTotal,"CR:",CR); + if (CRDatum.CRInsulin > 0) { + CRTotalCarbs += CRDatum.CRCarbs; + CRTotalInsulin += CRDatum.CRInsulinTotal; + } + }); + CRTotalInsulin = Math.round(CRTotalInsulin*1000)/1000; + totalCR = Math.round( CRTotalCarbs / CRTotalInsulin * 1000 )/1000; + console.error("CRTotalCarbs:",CRTotalCarbs,"CRTotalInsulin:",CRTotalInsulin,"totalCR:",totalCR); // convert the basal profile to hourly if it isn't already - hourlyBasalProfile = []; - hourlyPumpProfile = []; + var hourlyBasalProfile = []; + var hourlyPumpProfile = []; for (var i=0; i < 24; i++) { - // aututuned basal profile + // autotuned basal profile for (var j=0; j < basalProfile.length; ++j) { if (basalProfile[j].minutes <= i * 60) { if (basalProfile[j].rate == 0) { @@ -70,6 +101,7 @@ function tuneAllTheThings (inputs) { } //console.error(hourlyPumpProfile); //console.error(hourlyBasalProfile); + var newHourlyBasalProfile = JSON.parse(JSON.stringify(hourlyBasalProfile)); // look at net deviations for each hour for (var hour=0; hour < 24; hour++) { @@ -98,8 +130,8 @@ function tuneAllTheThings (inputs) { offsetHour = hour + offset; if (offsetHour < 0) { offsetHour += 24; } //console.error(offsetHour); - hourlyBasalProfile[offsetHour].rate += basalNeeded / 3; - hourlyBasalProfile[offsetHour].rate=Math.round(hourlyBasalProfile[offsetHour].rate*1000)/1000 + newHourlyBasalProfile[offsetHour].rate += basalNeeded / 3; + newHourlyBasalProfile[offsetHour].rate=Math.round(newHourlyBasalProfile[offsetHour].rate*1000)/1000 } // otherwise, figure out the percentage reduction required to the 1-3 hour prior basals // and adjust all of them downward proportionally @@ -108,41 +140,171 @@ function tuneAllTheThings (inputs) { for (var offset=-3; offset < 0; offset++) { offsetHour = hour + offset; if (offsetHour < 0) { offsetHour += 24; } - threeHourBasal += hourlyBasalProfile[offsetHour].rate; + threeHourBasal += newHourlyBasalProfile[offsetHour].rate; } var adjustmentRatio = 1.0 + basalNeeded / threeHourBasal; //console.error(adjustmentRatio); for (var offset=-3; offset < 0; offset++) { offsetHour = hour + offset; if (offsetHour < 0) { offsetHour += 24; } - hourlyBasalProfile[offsetHour].rate = hourlyBasalProfile[offsetHour].rate * adjustmentRatio; - hourlyBasalProfile[offsetHour].rate=Math.round(hourlyBasalProfile[offsetHour].rate*1000)/1000 + newHourlyBasalProfile[offsetHour].rate = newHourlyBasalProfile[offsetHour].rate * adjustmentRatio; + newHourlyBasalProfile[offsetHour].rate=Math.round(newHourlyBasalProfile[offsetHour].rate*1000)/1000 } } } if (pumpBasalProfile && pumpBasalProfile[0]) { for (var hour=0; hour < 24; hour++) { - //console.error(hourlyBasalProfile[hour],hourlyPumpProfile[hour].rate*1.2); + //console.error(newHourlyBasalProfile[hour],hourlyPumpProfile[hour].rate*1.2); // cap adjustments at autosens_max and autosens_min autotuneMax = pumpProfile.autosens_max; autotuneMin = pumpProfile.autosens_min; var maxRate = hourlyPumpProfile[hour].rate * autotuneMax; var minRate = hourlyPumpProfile[hour].rate * autotuneMin; - if (hourlyBasalProfile[hour].rate > maxRate ) { + if (newHourlyBasalProfile[hour].rate > maxRate ) { console.error("Limiting hour",hour,"basal to",maxRate.toFixed(2),"(which is",autotuneMax,"* pump basal of",hourlyPumpProfile[hour].rate,")"); //console.error("Limiting hour",hour,"basal to",maxRate.toFixed(2),"(which is 20% above pump basal of",hourlyPumpProfile[hour].rate,")"); - hourlyBasalProfile[hour].rate = maxRate; - } else if (hourlyBasalProfile[hour].rate < minRate ) { + newHourlyBasalProfile[hour].rate = maxRate; + } else if (newHourlyBasalProfile[hour].rate < minRate ) { console.error("Limiting hour",hour,"basal to",minRate.toFixed(2),"(which is",autotuneMin,"* pump basal of",hourlyPumpProfile[hour].rate,")"); //console.error("Limiting hour",hour,"basal to",minRate.toFixed(2),"(which is 20% below pump basal of",hourlyPumpProfile[hour].rate,")"); - hourlyBasalProfile[hour].rate = minRate; + newHourlyBasalProfile[hour].rate = minRate; + } + newHourlyBasalProfile[hour].rate = Math.round(newHourlyBasalProfile[hour].rate*1000)/1000; + } + } + + // some hours of the day rarely have data to tune basals due to meals. + // when no adjustments are needed to a particular hour, we should adjust it toward the average of the + // periods before and after it that do have data to be tuned + + var lastAdjustedHour = 0; + // scan through newHourlyBasalProfile and find hours where the rate is unchanged + for (var hour=0; hour < 24; hour++) { + if (hourlyBasalProfile[hour].rate === newHourlyBasalProfile[hour].rate) { + var nextAdjustedHour = 23; + for (var nextHour = hour; nextHour < 24; nextHour++) { + if (! (hourlyBasalProfile[nextHour].rate === newHourlyBasalProfile[nextHour].rate)) { + nextAdjustedHour = nextHour; + break; + //} else { + //console.error(nextHour, hourlyBasalProfile[nextHour].rate, newHourlyBasalProfile[nextHour].rate); + } } - hourlyBasalProfile[hour].rate = Math.round(hourlyBasalProfile[hour].rate*1000)/1000; + //console.error(hour, newHourlyBasalProfile); + newHourlyBasalProfile[hour].rate = Math.round( (0.8*hourlyBasalProfile[hour].rate + 0.1*newHourlyBasalProfile[lastAdjustedHour].rate + 0.1*newHourlyBasalProfile[nextAdjustedHour].rate)*1000 )/1000; + console.error("Adjusting hour",hour,"basal from",hourlyBasalProfile[hour].rate,"to",newHourlyBasalProfile[hour].rate,"based on hour",lastAdjustedHour,"=",newHourlyBasalProfile[lastAdjustedHour].rate,"and hour",nextAdjustedHour,"=",newHourlyBasalProfile[nextAdjustedHour].rate); + } else { + lastAdjustedHour = hour; } } - console.error(hourlyBasalProfile); - basalProfile = hourlyBasalProfile; + console.error(newHourlyBasalProfile); + basalProfile = newHourlyBasalProfile; + + // Calculate carb ratio (CR) independently of CSF and ISF + // Use the time period from meal bolus/carbs until COB is zero and IOB is < currentBasal/2 + // For now, if another meal IOB/COB stacks on top of it, consider them together + // Compare beginning and ending BGs, and calculate how much more/less insulin is needed to neutralize + // Use entered carbs vs. starting IOB + delivered insulin + needed-at-end insulin to directly calculate CR. + + + + // calculate net deviations while carbs are absorbing + // measured from carb entry until COB and deviations both drop to zero + + var deviations = 0; + var mealCarbs = 0; + var totalMealCarbs = 0; + var totalDeviations = 0; + var fullNewCSF; + //console.error(CSFGlucose[0].mealAbsorption); + //console.error(CSFGlucose[0]); + for (var i=0; i < CSFGlucose.length; ++i) { + //console.error(CSFGlucose[i].mealAbsorption, i); + if ( CSFGlucose[i].mealAbsorption === "start" ) { + deviations = 0; + mealCarbs = parseInt(CSFGlucose[i].mealCarbs); + } else if (CSFGlucose[i].mealAbsorption === "end") { + deviations += parseFloat(CSFGlucose[i].deviation); + // compare the sum of deviations from start to end vs. current CSF * mealCarbs + //console.error(CSF,mealCarbs); + csfRise = CSF * mealCarbs; + //console.error(deviations,ISF); + //console.error("csfRise:",csfRise,"deviations:",deviations); + totalMealCarbs += mealCarbs; + totalDeviations += deviations; + + } else { + deviations += Math.max(0*previousAutotune.min_5m_carbimpact,parseFloat(CSFGlucose[i].deviation)); + mealCarbs = Math.max(mealCarbs, parseInt(CSFGlucose[i].mealCarbs)); + } + } + // at midnight, write down the mealcarbs as total meal carbs (to prevent special case of when only one meal and it not finishing absorbing by midnight) + // TODO: figure out what to do with dinner carbs that don't finish absorbing by midnight + if (totalMealCarbs == 0) { totalMealCarbs += mealCarbs; } + if (totalDeviations == 0) { totalDeviations += deviations; } + //console.error(totalDeviations, totalMealCarbs); + if (totalMealCarbs == 0) { + // if no meals today, CSF is unchanged + fullNewCSF = CSF; + } else { + // how much change would be required to account for all of the deviations + fullNewCSF = Math.round( (totalDeviations / totalMealCarbs)*100 )/100; + } + // only adjust by 20% + newCSF = ( 0.8 * CSF ) + ( 0.2 * fullNewCSF ); + // safety cap CSF + if (typeof(pumpCSF) !== 'undefined') { + var maxCSF = pumpCSF * autotuneMax; + var minCSF = pumpCSF * autotuneMin; + if (newCSF > maxCSF) { + console.error("Limiting CSF to",maxCSF.toFixed(2),"(which is",autotuneMax,"* pump CSF of",pumpCSF,")"); + newCSF = maxCSF; + } else if (newCSF < minCSF) { + console.error("Limiting CSF to",minCSF.toFixed(2),"(which is",autotuneMin,"* pump CSF of",pumpCSF,")"); + newCSF = minCSF; + } //else { console.error("newCSF",newCSF,"is close enough to",pumpCSF); } + } + oldCSF = Math.round( CSF * 1000 ) / 1000; + newCSF = Math.round( newCSF * 1000 ) / 1000; + totalDeviations = Math.round ( totalDeviations * 1000 )/1000; + console.error("totalMealCarbs:",totalMealCarbs,"totalDeviations:",totalDeviations,"oldCSF",oldCSF,"fullNewCSF:",fullNewCSF,"newCSF:",newCSF); + // this is where CSF is set based on the outputs + if (newCSF) { + CSF = newCSF; + } + + if (totalCR == 0) { + // if no meals today, CR is unchanged + fullNewCR = carbRatio; + } else { + // how much change would be required to account for all of the deviations + fullNewCR = totalCR; + } + // only adjust by 10% + newCR = ( 0.8 * carbRatio ) + ( 0.2 * fullNewCR ); + // safety cap CR + if (typeof(pumpCarbRatio) !== 'undefined') { + var maxCR = pumpCarbRatio * autotuneMax; + var minCR = pumpCarbRatio * autotuneMin; + if (newCR > maxCR) { + console.error("Limiting CR to",maxCR.toFixed(2),"(which is",autotuneMax,"* pump CR of",pumpCarbRatio,")"); + newCR = maxCR; + } else if (newCR < minCR) { + console.error("Limiting CR to",minCR.toFixed(2),"(which is",autotuneMin,"* pump CR of",pumpCarbRatio,")"); + newCR = minCR; + } //else { console.error("newCR",newCR,"is close enough to",pumpCarbRatio); } + } + newCR = Math.round( newCR * 1000 ) / 1000; + console.error("oldCR:",carbRatio,"fullNewCR:",fullNewCR,"newCR:",newCR); + // this is where CR is set based on the outputs + var ISFFromCRAndCSF = ISF; + if (newCR) { + carbRatio = newCR; + ISFFromCRAndCSF = Math.round( carbRatio * CSF * 1000)/1000; + } + + // calculate median deviation and bgi in data attributable to ISF var deviations = []; @@ -195,6 +357,12 @@ function tuneAllTheThings (inputs) { adjustedISF = minISF; } + // average both the directly-calculated ISF and the ISFFromCRAndCSF if we're reasonably well tuned + if (p50ratios > 0.4 && p50ratios < 0.6) { + // TODO: figure out if there's a way to do this without messing up CSF tuning + // adjustedISF = (adjustedISF + ISFFromCRAndCSF) / 2; + } + // and apply 10% of that adjustment var newISF = ( 0.9 * ISF ) + ( 0.1 * adjustedISF ); @@ -213,70 +381,15 @@ function tuneAllTheThings (inputs) { newISF = Math.round( newISF * 1000 ) / 1000; //console.error(avgRatio); //console.error(newISF); + p50deviation = Math.round( p50deviation * 1000 ) / 1000; + p50BGI = Math.round( p50BGI * 1000 ) / 1000; + adjustedISF = Math.round( adjustedISF * 1000 ) / 1000; console.error("p50deviation:",p50deviation,"p50BGI",p50BGI,"p50ratios:",p50ratios,"Old ISF:",ISF,"fullNewISF:",fullNewISF,"adjustedISF:",adjustedISF,"newISF:",newISF); - ISF = newISF; - - // calculate net deviations while carbs are absorbing - // measured from carb entry until COB and deviations both drop to zero - - var deviations = 0; - var mealCarbs = 0; - var totalMealCarbs = 0; - var totalDeviations = 0; - var fullNewCSF; - //console.error(CSFGlucose[0].mealAbsorption); - //console.error(CSFGlucose[0]); - for (var i=0; i < CSFGlucose.length; ++i) { - //console.error(CSFGlucose[i].mealAbsorption, i); - if ( CSFGlucose[i].mealAbsorption === "start" ) { - deviations = 0; - mealCarbs = parseInt(CSFGlucose[i].mealCarbs); - } else if (CSFGlucose[i].mealAbsorption === "end") { - deviations += parseFloat(CSFGlucose[i].deviation); - // compare the sum of deviations from start to end vs. current CSF * mealCarbs - //console.error(CSF,mealCarbs); - csfRise = CSF * mealCarbs; - //console.error(deviations,ISF); - //console.error("csfRise:",csfRise,"deviations:",deviations); - totalMealCarbs += mealCarbs; - totalDeviations += deviations; - - } else { - deviations += Math.max(0*previousAutotune.min_5m_carbimpact,parseFloat(CSFGlucose[i].deviation)); - mealCarbs = Math.max(mealCarbs, parseInt(CSFGlucose[i].mealCarbs)); - } + if (newISF) { + ISF = newISF; } - // at midnight, write down the mealcarbs as total meal carbs (to prevent special case of when only one meal and it not finishing absorbing by midnight) - // TODO: figure out what to do with dinner carbs that don't finish absorbing by midnight - if (totalMealCarbs == 0) { totalMealCarbs += mealCarbs; } - if (totalDeviations == 0) { totalDeviations += deviations; } - //console.error(totalDeviations, totalMealCarbs); - if (totalMealCarbs == 0) { - // if no meals today, CSF is unchanged - fullNewCSF = CSF; - } else { - // how much change would be required to account for all of the deviations - fullNewCSF = Math.round( (totalDeviations / totalMealCarbs)*100 )/100; - } - // only adjust by 10% - newCSF = ( 0.9 * CSF ) + ( 0.1 * fullNewCSF ); - // safety cap CSF - if (typeof(pumpCSF) !== 'undefined') { - var maxCSF = pumpCSF * autotuneMax; - var minCSF = pumpCSF * autotuneMin; - if (newCSF > maxCSF) { - console.error("Limiting CSF to",maxCSF.toFixed(2),"(which is",autotuneMax,"* pump CSF of",pumpCSF,")"); - newCSF = maxCSF; - } else if (newCSF < minCSF) { - console.error("Limiting CSF to",minCSF.toFixed(2),"(which is",autotuneMin,"* pump CSF of",pumpCSF,")"); - newCSF = minCSF; - } //else { console.error("newCSF",newCSF,"is close enough to",pumpCSF); } - } - newCSF = Math.round( newCSF * 1000 ) / 1000; - console.error("totalMealCarbs:",totalMealCarbs,"totalDeviations:",totalDeviations,"fullNewCSF:",fullNewCSF,"newCSF:",newCSF); - // this is where CSF is set based on the outputs - CSF = newCSF; + // reconstruct updated version of previousAutotune as autotuneOutput autotuneOutput = previousAutotune; @@ -285,7 +398,7 @@ function tuneAllTheThings (inputs) { autotuneOutput.isfProfile = isfProfile; autotuneOutput.sens = ISF; autotuneOutput.csf = CSF; - carbRatio = ISF / CSF; + //carbRatio = ISF / CSF; carbRatio = Math.round( carbRatio * 1000 ) / 1000; autotuneOutput.carb_ratio = carbRatio; From d498552fdeb46c6d004078b04ae59b62ad834185 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 10 Sep 2017 13:56:00 -0700 Subject: [PATCH 065/215] Make remainingCI time responsive to temp targets (#646) * make 2h remainingCIpeak and 4h remainingCATime a variable * adjust remainingCATime based on temp target * clearer logging output --- lib/determine-basal/determine-basal.js | 43 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index ceb49c573..a34f51d56 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -302,9 +302,20 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //console.error(csf * meal_data.carbs); // meal_carbimpact (mg/dL/5m) = CSF (mg/dL/g) * carbs (g) / 6 (h) * (1h/60m) * 5 (m/5m) * 2 (for linear decay) //var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1) - // calculate the number of carbs absorbed over 4h at current CI + // assume that all carbs will absorb over 4 more hours w/ normal targets + var remainingCATime = 4; + // if an eating soon low temp target is set, assume a 3h absorption time (for 80 mg/dL) + if (profile.temptargetSet && ( target_bg < 90 || target_bg > 110 )) { + // conversely, assume 5h for 120, 6h for 140, etc. + // number of hours to adjust remainingCATime. 80 -> -1, 120 -> +1, 140 -> +2 + remainingCATimeAdjustment = (target_bg - 100) / 20; + remainingCATime += remainingCATimeAdjustment; + console.error("Adjusting remainingCATime to",remainingCATime,"h based on temp target of",target_bg); + } + + // calculate the number of carbs absorbed over remainingCATime hours at current CI // CI (mg/dL/5m) * (5m)/5 (m) * 60 (min/hr) * 4 (h) / 2 (linear decay factor) = total carb impact (mg/dL) - var totalCI = Math.max(0, ci / 5 * 60 * 4 / 2); + var totalCI = Math.max(0, ci / 5 * 60 * remainingCATime / 2); // totalCI (mg/dL) / CSF (mg/dL/g) = total carbs absorbed (g) var totalCA = totalCI / csf; var remainingCarbsCap = 90; // default to 90 @@ -314,13 +325,12 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var remainingCarbsIgnore = 1 - remainingCarbsFraction; var remainingCarbs = Math.max(0, meal_data.mealCOB - totalCA - meal_data.carbs*remainingCarbsIgnore); remainingCarbs = Math.min(remainingCarbsCap,remainingCarbs); - // assume remainingCarbs will absorb in a /\ shaped bilinear curve peaking at 2h and ending at 4h - // area of the /\ triangle is the same as a remainingCIpeak-height rectangle out to 2h - // remainingCIpeak (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / 2 (h) - var remainingCIpeak = remainingCarbs * csf * 5 / 60 / 2; - // remainingCI (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / 4 (h) - //var remainingCI = remainingCarbs * csf * 5 / 60 / 4; - //console.error(profile.min_5m_carbimpact,ci,totalCI,totalCA,remainingCarbs,remainingCI); + // assume remainingCarbs will absorb in a /\ shaped bilinear curve + // peaking at remainingCATime / 2 and ending at remainingCATime hours + // area of the /\ triangle is the same as a remainingCIpeak-height rectangle out to remainingCATime/2 + // remainingCIpeak (mg/dL/5m) = remainingCarbs (g) * CSF (mg/dL/g) * 5 (m/5m) * 1h/60m / (remainingCATime/2) (h) + var remainingCIpeak = remainingCarbs * csf * 5 / 60 / (remainingCATime/2); + //console.error(profile.min_5m_carbimpact,ci,totalCI,totalCA,remainingCarbs,remainingCI,remainingCATime); //if (meal_data.mealCOB * 3 > meal_data.carbs) { } // calculate peak deviation in last hour, and slope from that to current deviation @@ -330,8 +340,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ aci = 10; //5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m) // duration (in 5m data points) = COB (g) * CSF (mg/dL/g) / ci (mg/dL/5m) - // limit cid to 4 hours: the reset goes to remainingCI - cid = Math.min(4*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci )); + // limit cid to remainingCATime hours: the reset goes to remainingCI + cid = Math.min(remainingCATime*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci )); acid = Math.max(0, meal_data.mealCOB * csf / aci ); // duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay) console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (2h peak):",round(remainingCIpeak,1),"mg/dL per 5m"); @@ -367,10 +377,11 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // eventually accounting for all carbs (if they can be absorbed over DIA) predCI = Math.max(0, Math.max(0,ci) * ( 1 - COBpredBGs.length/Math.max(cid*2,1) ) ); predACI = Math.max(0, Math.max(0,aci) * ( 1 - COBpredBGs.length/Math.max(acid*2,1) ) ); - // if any carbs aren't absorbed after 4 hours, assume they'll absorb in a /\ shaped - // bilinear curve peaking at remainingCIpeak at 2h (24*5m) and ending at 4h (48*5m intervals) - var intervals = Math.min( COBpredBGs.length, 48-COBpredBGs.length ); - var remainingCI = Math.max(0, intervals / 24 * remainingCIpeak ); + // if any carbs aren't absorbed after remainingCATime hours, assume they'll absorb in a /\ shaped + // bilinear curve peaking at remainingCIpeak at remainingCATime/2 hours (remainingCATime/2*12 * 5m) + // and ending at remainingCATime h (remainingCATime*12 * 5m intervals) + var intervals = Math.min( COBpredBGs.length, (remainingCATime*12)-COBpredBGs.length ); + var remainingCI = Math.max(0, intervals / (remainingCATime/2*12) * remainingCIpeak ); remainingCItotal += predCI+remainingCI; remainingCIs.push(round(remainingCI,1)); predCIs.push(round(predCI,1)); @@ -834,7 +845,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // (or enough insulin to cover COB, or maxBolus, whichever is smallest) if ( iob_data.iob < mealInsulinReq ) { initialMealInsulinReq = round(mealInsulinReq-iob_data.iob,1); - console.error("IOB",iob_data.iob,"<< COB",meal_data.mealCOB+"; insulinReq/2 =",insulinReq/2+"; initialMealInsulinReq =",initialMealInsulinReq); + console.error("IOB",iob_data.iob,"< COB",meal_data.mealCOB+"; insulinReq/2 =",insulinReq/2+"; initialMealInsulinReq =",initialMealInsulinReq); if (initialMealInsulinReq > microBolus) { microBolus = round(Math.min(insulinReq/2,maxBolus,initialMealInsulinReq),1); } From 8e6a44f2e396247ef446badf6ae13ad85f2f9f94 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 19 Sep 2017 17:43:31 -0700 Subject: [PATCH 066/215] only display rate and duration from enact/smb-enacted.json (#654) --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 0628426b8..d368a31e5 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -143,7 +143,7 @@ function smb_enact_temp { openaps report invoke enact/smb-enacted.json 2>&1 >/dev/null | tail -1 grep -q duration enact/smb-enacted.json || openaps invoke enact/smb-enacted.json 2>&1 >/dev/null | tail -1 cp -up enact/smb-enacted.json enact/enacted.json - echo -n "enact/smb-enacted.json: " && cat enact/smb-enacted.json | jq -C -c . + echo -n "enact/smb-enacted.json: " && cat enact/smb-enacted.json | jq -C -c '. | "Rate: \(.rate) Duration: \(.duration)"' ) 2>&1 | egrep -v "^ |subg_rfspy|handler" else echo -n "No smb_enact needed. " From d78d8807c883bb72e37f890e7e10920433762771 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 19 Sep 2017 18:02:21 -0700 Subject: [PATCH 067/215] don't adjust temptargets (#656) --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index a34f51d56..e0d673efb 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -192,7 +192,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var snoozeBG = naive_snoozeBG + deviation; // adjust target BG range if needed to safely bring down high BG faster without causing lows - if ( bg > max_bg && profile.adv_target_adjustments ) { + if ( bg > max_bg && profile.adv_target_adjustments && ! profile.temptargetSet ) { // with target=100, as BG rises from 100 to 160, adjustedTarget drops from 100 to 80 var adjustedMinBG = round(Math.max(80, min_bg - (bg - min_bg)/3 ),0); var adjustedTargetBG =round( Math.max(80, target_bg - (bg - target_bg)/3 ),0); From 1f085189426cdeb13cfb7bc3b29fb5a0a8f3c238 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 19 Sep 2017 18:39:45 -0700 Subject: [PATCH 068/215] avoid divide by zero (NaN) in CI Duration (#657) --- lib/determine-basal/determine-basal.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index e0d673efb..63de4a331 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -341,7 +341,12 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m) // duration (in 5m data points) = COB (g) * CSF (mg/dL/g) / ci (mg/dL/5m) // limit cid to remainingCATime hours: the reset goes to remainingCI - cid = Math.min(remainingCATime*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci )); + if (ci == 0) { + // avoid divide by zero + cid = 0; + } else { + cid = Math.min(remainingCATime*60/5/2,Math.max(0, meal_data.mealCOB * csf / ci )); + } acid = Math.max(0, meal_data.mealCOB * csf / aci ); // duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay) console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (2h peak):",round(remainingCIpeak,1),"mg/dL per 5m"); From d5dbfe9ce6cdc6a1b99e2d59280b4fe443a4f3d9 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 19 Sep 2017 19:25:26 -0700 Subject: [PATCH 069/215] adjust remainingCATime gradually from 3h up to 4h @ 25% of carbs absorbed --- lib/determine-basal/determine-basal.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index e0d673efb..7835e2a45 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -304,6 +304,15 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1) // assume that all carbs will absorb over 4 more hours w/ normal targets var remainingCATime = 4; + // if fewer than 25% of carbs have absorbed, adjust remainingCATime gradually from 3h up to 4h + if ( meal_data.mealCOB > 0.75 * meal_data.carbs ) { + // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.75*carbs -> 0 + fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); + remainingCATimeAdjustment = Math.min(1,(fractionCOBAbsorbed*4))-1; + remainingCATime += remainingCATimeAdjustment; + //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) + console.error("Adjusting remainingCATime to",remainingCATime,"h based on",fractionCOBAbsorbed*100+"% carb absorption"); + } // if an eating soon low temp target is set, assume a 3h absorption time (for 80 mg/dL) if (profile.temptargetSet && ( target_bg < 90 || target_bg > 110 )) { // conversely, assume 5h for 120, 6h for 140, etc. From f9ee0b59e7d5ba300a4e35f7715c34024f90d25c Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 19 Sep 2017 20:01:00 -0700 Subject: [PATCH 070/215] adjust remainingCATime for <50% absorbed, exclusive of temptarget adjustments --- lib/determine-basal/determine-basal.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 7835e2a45..142d188d0 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -304,15 +304,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1) // assume that all carbs will absorb over 4 more hours w/ normal targets var remainingCATime = 4; - // if fewer than 25% of carbs have absorbed, adjust remainingCATime gradually from 3h up to 4h - if ( meal_data.mealCOB > 0.75 * meal_data.carbs ) { - // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.75*carbs -> 0 - fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); - remainingCATimeAdjustment = Math.min(1,(fractionCOBAbsorbed*4))-1; - remainingCATime += remainingCATimeAdjustment; - //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) - console.error("Adjusting remainingCATime to",remainingCATime,"h based on",fractionCOBAbsorbed*100+"% carb absorption"); - } // if an eating soon low temp target is set, assume a 3h absorption time (for 80 mg/dL) if (profile.temptargetSet && ( target_bg < 90 || target_bg > 110 )) { // conversely, assume 5h for 120, 6h for 140, etc. @@ -320,6 +311,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ remainingCATimeAdjustment = (target_bg - 100) / 20; remainingCATime += remainingCATimeAdjustment; console.error("Adjusting remainingCATime to",remainingCATime,"h based on temp target of",target_bg); + // if fewer than 50% of carbs have absorbed, adjust remainingCATime gradually from 3h up to 4h + } else if ( meal_data.mealCOB > 0.5 * meal_data.carbs ) { + // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.5*carbs -> 0 + fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); + remainingCATimeAdjustment = Math.min(1,(fractionCOBAbsorbed*2))-1; + remainingCATime += remainingCATimeAdjustment; + //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) + console.error("Adjusting remainingCATime to",remainingCATime,"h based on",fractionCOBAbsorbed*100+"% carb absorption"); } // calculate the number of carbs absorbed over remainingCATime hours at current CI From d61fa925a7367b4d70bc1416dfe176b5bf5425d6 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 19 Sep 2017 20:07:14 -0700 Subject: [PATCH 071/215] adjust remainingCATime longer when <50% of carbs remain and we aren't seeing absorption --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 142d188d0..fdc2fd859 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -312,7 +312,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ remainingCATime += remainingCATimeAdjustment; console.error("Adjusting remainingCATime to",remainingCATime,"h based on temp target of",target_bg); // if fewer than 50% of carbs have absorbed, adjust remainingCATime gradually from 3h up to 4h - } else if ( meal_data.mealCOB > 0.5 * meal_data.carbs ) { + } else { // if ( meal_data.mealCOB > 0.5 * meal_data.carbs ) { // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.5*carbs -> 0 fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); remainingCATimeAdjustment = Math.min(1,(fractionCOBAbsorbed*2))-1; From 6494a7e958b8f99c3f14f8dc5f5f35321ae8a7f7 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 19 Sep 2017 20:32:32 -0700 Subject: [PATCH 072/215] actually allow positive remainingCATimeAdjustment --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index fdc2fd859..cee649ab1 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -315,7 +315,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } else { // if ( meal_data.mealCOB > 0.5 * meal_data.carbs ) { // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.5*carbs -> 0 fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); - remainingCATimeAdjustment = Math.min(1,(fractionCOBAbsorbed*2))-1; + remainingCATimeAdjustment = fractionCOBAbsorbed*2 - 1; remainingCATime += remainingCATimeAdjustment; //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) console.error("Adjusting remainingCATime to",remainingCATime,"h based on",fractionCOBAbsorbed*100+"% carb absorption"); From 9de3a99f9ea6f59b10a5c590307118f037c823d8 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 19 Sep 2017 20:35:22 -0700 Subject: [PATCH 073/215] round away floating point math --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index cee649ab1..6987fb443 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -315,7 +315,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } else { // if ( meal_data.mealCOB > 0.5 * meal_data.carbs ) { // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.5*carbs -> 0 fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); - remainingCATimeAdjustment = fractionCOBAbsorbed*2 - 1; + remainingCATimeAdjustment = round( fractionCOBAbsorbed*2 - 1, 2); remainingCATime += remainingCATimeAdjustment; //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) console.error("Adjusting remainingCATime to",remainingCATime,"h based on",fractionCOBAbsorbed*100+"% carb absorption"); From 1d78bb2384dc3c642aac0122d3dda46c0f1ba06c Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 19 Sep 2017 21:25:23 -0700 Subject: [PATCH 074/215] comment out remainingCATimeAdjustment for temptargets --- lib/determine-basal/determine-basal.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 6987fb443..9d902b776 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -304,6 +304,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1) // assume that all carbs will absorb over 4 more hours w/ normal targets var remainingCATime = 4; +/* // if an eating soon low temp target is set, assume a 3h absorption time (for 80 mg/dL) if (profile.temptargetSet && ( target_bg < 90 || target_bg > 110 )) { // conversely, assume 5h for 120, 6h for 140, etc. @@ -313,13 +314,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ console.error("Adjusting remainingCATime to",remainingCATime,"h based on temp target of",target_bg); // if fewer than 50% of carbs have absorbed, adjust remainingCATime gradually from 3h up to 4h } else { // if ( meal_data.mealCOB > 0.5 * meal_data.carbs ) { +*/ // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.5*carbs -> 0 fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); remainingCATimeAdjustment = round( fractionCOBAbsorbed*2 - 1, 2); remainingCATime += remainingCATimeAdjustment; //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) console.error("Adjusting remainingCATime to",remainingCATime,"h based on",fractionCOBAbsorbed*100+"% carb absorption"); - } +// } // calculate the number of carbs absorbed over remainingCATime hours at current CI // CI (mg/dL/5m) * (5m)/5 (m) * 60 (min/hr) * 4 (h) / 2 (linear decay factor) = total carb impact (mg/dL) From 40a937d48c86918141ffe1720c5ff450fdb3732e Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 19 Sep 2017 21:51:29 -0700 Subject: [PATCH 075/215] round away floating point math --- lib/determine-basal/determine-basal.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 9d902b776..461f13e36 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -317,8 +317,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ */ // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.5*carbs -> 0 fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); - remainingCATimeAdjustment = round( fractionCOBAbsorbed*2 - 1, 2); + remainingCATimeAdjustment = fractionCOBAbsorbed*2 - 1; remainingCATime += remainingCATimeAdjustment; + remainingCATime = round(remainingCATime,1); //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) console.error("Adjusting remainingCATime to",remainingCATime,"h based on",fractionCOBAbsorbed*100+"% carb absorption"); // } From 55c9b428d82e5f383a1843c2148fd723dd0c4649 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 20 Sep 2017 10:05:21 -0700 Subject: [PATCH 076/215] only adjust remainingCATime if there are meal_data.carbs --- lib/determine-basal/determine-basal.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 461f13e36..c7173e537 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -304,17 +304,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1) // assume that all carbs will absorb over 4 more hours w/ normal targets var remainingCATime = 4; -/* - // if an eating soon low temp target is set, assume a 3h absorption time (for 80 mg/dL) - if (profile.temptargetSet && ( target_bg < 90 || target_bg > 110 )) { - // conversely, assume 5h for 120, 6h for 140, etc. - // number of hours to adjust remainingCATime. 80 -> -1, 120 -> +1, 140 -> +2 - remainingCATimeAdjustment = (target_bg - 100) / 20; - remainingCATime += remainingCATimeAdjustment; - console.error("Adjusting remainingCATime to",remainingCATime,"h based on temp target of",target_bg); - // if fewer than 50% of carbs have absorbed, adjust remainingCATime gradually from 3h up to 4h - } else { // if ( meal_data.mealCOB > 0.5 * meal_data.carbs ) { -*/ + if (meal_data.carbs) { // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.5*carbs -> 0 fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); remainingCATimeAdjustment = fractionCOBAbsorbed*2 - 1; @@ -322,7 +312,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ remainingCATime = round(remainingCATime,1); //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) console.error("Adjusting remainingCATime to",remainingCATime,"h based on",fractionCOBAbsorbed*100+"% carb absorption"); -// } + } // calculate the number of carbs absorbed over remainingCATime hours at current CI // CI (mg/dL/5m) * (5m)/5 (m) * 60 (min/hr) * 4 (h) / 2 (linear decay factor) = total carb impact (mg/dL) From 071e5d4c61eccf9199e73956496c96059047dc00 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 20 Sep 2017 10:06:46 -0700 Subject: [PATCH 077/215] only display remainingCI debugging with COB --- lib/determine-basal/determine-basal.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index c7173e537..ade40127c 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -423,9 +423,11 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } catch (e) { console.error("Problem with iobArray. Optional feature Advanced Meal Assist disabled:",e); } - console.error("predCIs:",predCIs.join(" ")); - console.error("remainingCIs:",remainingCIs.join(" ")); - console.error("COB:",meal_data.mealCOB,"remainingCItotal/csf:",round(remainingCItotal/csf,2),"remainingCarbs:",round(remainingCarbs,2)); + if (meal_data.mealCOB) { + console.error("predCIs (mg/dL/5m):",predCIs.join(" ")); + console.error("remainingCIs:",remainingCIs.join(" ")); + console.error("COB:",meal_data.mealCOB,"remainingCItotal/csf:",round(remainingCItotal/csf,2),"remainingCarbs:",round(remainingCarbs,2)); + } //,"totalCA:",round(totalCA,2),"remainingCItotal/csf+totalCA:",round(remainingCItotal/csf+totalCA,2)); rT.predBGs = {}; IOBpredBGs.forEach(function(p, i, theArray) { From 235a085a5097355d0039d75c2e026fbb6536f5aa Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 20 Sep 2017 14:14:34 -0700 Subject: [PATCH 078/215] make SMB model failure explicit --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index d368a31e5..8f02504fd 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -318,7 +318,7 @@ function preflight { echo -n "Preflight " # only 515, 522, 523, 715, 722, 723, 554, and 754 pump models have been tested with SMB ( openaps report invoke settings/model.json || openaps report invoke settings/model.json ) 2>&1 >/dev/null | tail -1 \ - && egrep -q "[57](15|22|23|54)" settings/model.json \ + && ( egrep -q "[57](15|22|23|54)" settings/model.json || (echo "error: pump model untested with SMB: "; false) ) \ && echo -n "OK. " \ || ( echo -n "fail. "; false ) } From 70b8f9789e93d05a2ee4a382888ebd458a3a3f38 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 20 Sep 2017 14:23:19 -0700 Subject: [PATCH 079/215] echo -n --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 8f02504fd..d00b4db2a 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -318,7 +318,7 @@ function preflight { echo -n "Preflight " # only 515, 522, 523, 715, 722, 723, 554, and 754 pump models have been tested with SMB ( openaps report invoke settings/model.json || openaps report invoke settings/model.json ) 2>&1 >/dev/null | tail -1 \ - && ( egrep -q "[57](15|22|23|54)" settings/model.json || (echo "error: pump model untested with SMB: "; false) ) \ + && ( egrep -q "[57](15|22|23|54)" settings/model.json || (echo -n "error: pump model untested with SMB: "; false) ) \ && echo -n "OK. " \ || ( echo -n "fail. "; false ) } From 1d1041e3d07086e989394390a3d0bb1cc80afc23 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 20 Sep 2017 15:04:43 -0700 Subject: [PATCH 080/215] skip bolusing check for 512/712 --- bin/oref0-pump-loop.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index d00b4db2a..011bb320c 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -394,7 +394,8 @@ function wait_for_silence { function gather { openaps report invoke monitor/status.json 2>&1 >/dev/null | tail -1 \ && echo -n Ref \ - && ( test $(cat monitor/status.json | json suspended) == true || \ + && ( grep "model.*12" monitor/status.json || \ + test $(cat monitor/status.json | json suspended) == true || \ test $(cat monitor/status.json | json bolusing) == false ) \ && echo -n resh \ && ( openaps monitor-pump || openaps monitor-pump ) 2>&1 >/dev/null | tail -1 \ From b356e5d0f325eccd40474b7701da6e00945dffe2 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 20 Sep 2017 15:19:31 -0700 Subject: [PATCH 081/215] grep quietly --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 011bb320c..157b5eaf8 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -394,7 +394,7 @@ function wait_for_silence { function gather { openaps report invoke monitor/status.json 2>&1 >/dev/null | tail -1 \ && echo -n Ref \ - && ( grep "model.*12" monitor/status.json || \ + && ( grep -q "model.*12" monitor/status.json || \ test $(cat monitor/status.json | json suspended) == true || \ test $(cat monitor/status.json | json bolusing) == false ) \ && echo -n resh \ From 320d69ac96090bb6ee6667c871cf7215337cdf55 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 20 Sep 2017 16:07:02 -0700 Subject: [PATCH 082/215] 0.5.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5f00da705..58dceed74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oref0", - "version": "0.5.3", + "version": "0.5.4", "description": "openaps oref0 reference implementation of the reference design", "scripts": { "test": "make test", From 6a0e831ab846f1484ffed00333da32aa3b737327 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 20 Sep 2017 17:09:57 -0700 Subject: [PATCH 083/215] display curve in preferences by default (#658) --- lib/profile/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/profile/index.js b/lib/profile/index.js index ee3d3b2b1..1c2b06356 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -59,6 +59,7 @@ function displayedDefaults () { profile.enableSMB_with_COB = allDefaults.enableSMB_with_COB; profile.enableSMB_with_temptarget = allDefaults.enableSMB_with_temptarget; profile.enableUAM = allDefaults.enableUAM; + profile.curve = allDefaults.curve; console.error(profile); return profile From 19a2e36d0539f7e8446cb5750051963b8119a9d0 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 20 Sep 2017 17:13:30 -0700 Subject: [PATCH 084/215] Less aggressive UAM (#655) * rename minDeviationSlope to slopeFromMaxDeviation * rename minDeviationSlope to slopeFromMaxDeviation * assume deviations will drop back down at least at 1/3 the rate they ramped up * remove debugging * only use minUAMPredBG if it's higher than minIOBPredBG * Revert "only use minUAMPredBG if it's higher than minIOBPredBG" This reverts commit 9bcb5b65f8fe7919c098bfda8e88f332fb634a93. * if minUAMPredBG < minIOBPredBG, set minUAMPredBG to their average * it's UAMpredBG I want to adjust, not minUAMPredBG * use minDelta (15m) instead of minAvgDelta (30m) for UAM now * revert "if UAMpredBG < IOBpredBG, use their average instead" * finish revert of "if UAMpredBG < IOBpredBG, use their average instead" --- lib/determine-basal/cob.js | 26 ++++++++++++++++++-------- lib/determine-basal/determine-basal.js | 20 ++++++++++++-------- lib/meal/total.js | 6 ++++-- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/lib/determine-basal/cob.js b/lib/determine-basal/cob.js index 3eacceef1..06f5073cc 100644 --- a/lib/determine-basal/cob.js +++ b/lib/determine-basal/cob.js @@ -98,15 +98,17 @@ function detectCarbAbsorption(inputs) { } } var currentDeviation; - var minDeviationSlope = 0; + var slopeFromMaxDeviation = 0; + var slopeFromMinDeviation = 999; var maxDeviation = 0; + var minDeviation = 999; //console.error(bucketed_data); for (var i=0; i < bucketed_data.length-3; ++i) { var bgTime = new Date(bucketed_data[i].date); var sens = isf.isfLookup(profile.isfProfile,bgTime); - //console.error(bgTime , bucketed_data[i].glucose); + //console.error(bgTime , bucketed_data[i].glucose, bucketed_data[i].date); var bg; var avgDelta; var delta; @@ -127,7 +129,7 @@ function detectCarbAbsorption(inputs) { //console.error("Before: ", new Date().getTime()); var iob = get_iob(iob_inputs, true, treatments)[0]; //console.error("After: ", new Date().getTime()); - //console.log(JSON.stringify(iob)); + //console.error(JSON.stringify(iob)); var bgi = Math.round(( -iob.activity * sens * 5 )*100)/100; bgi = bgi.toFixed(2); @@ -139,7 +141,7 @@ function detectCarbAbsorption(inputs) { if (i==0) { currentDeviation = Math.round((avgDelta-bgi)*1000)/1000; if (ciTime > bgTime) { - //console.error("currentDeviation:",currentDeviation); + //console.error("currentDeviation:",currentDeviation,avgDelta,bgi); } if (currentDeviation/2 > profile.min_5m_carbimpact) { //console.error("currentDeviation",currentDeviation,"/2 > min_5m_carbimpact",profile.min_5m_carbimpact); @@ -147,11 +149,17 @@ function detectCarbAbsorption(inputs) { } else if (ciTime > bgTime) { avgDeviation = Math.round((avgDelta-bgi)*1000)/1000; deviationSlope = (avgDeviation-currentDeviation)/(bgTime-ciTime)*1000*60*5; + //console.error(avgDeviation,currentDeviation,bgTime,ciTime) if (avgDeviation > maxDeviation) { - minDeviationSlope = Math.min(0, deviationSlope); + slopeFromMaxDeviation = Math.min(0, deviationSlope); maxDeviation = avgDeviation; } - //console.error("Deviations:",bgTime, avgDeviation, deviationSlope, minDeviationSlope); + if (avgDeviation < minDeviation) { + slopeFromMinDeviation = Math.max(0, deviationSlope); + minDeviation = avgDeviation; + } + + //console.error("Deviations:",bgTime, avgDeviation, deviationSlope, slopeFromMaxDeviation, slopeFromMinDeviation, avgDelta,bgi); } // if bgTime is more recent than mealTime @@ -166,14 +174,16 @@ function detectCarbAbsorption(inputs) { } } if(maxDeviation>0) { - //console.error("currentDeviation:",currentDeviation,"maxDeviation:",maxDeviation,"minDeviationSlope:",minDeviationSlope); + //console.error("currentDeviation:",currentDeviation,"maxDeviation:",maxDeviation,"slopeFromMaxDeviation:",slopeFromMaxDeviation); } var output = { "carbsAbsorbed": carbsAbsorbed , "currentDeviation": currentDeviation , "maxDeviation": maxDeviation - , "minDeviationSlope": minDeviationSlope + , "minDeviation": minDeviation + , "slopeFromMaxDeviation": slopeFromMaxDeviation + , "slopeFromMinDeviation": slopeFromMinDeviation } return output; } diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 63de4a331..312159834 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -292,7 +292,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // calculate current carb absorption rate, and how long to absorb all carbs // CI = current carb impact on BG in mg/dL/5m ci = round((minDelta - bgi),1); - uci = round((minAvgDelta - bgi),1); + uci = round((minDelta - bgi),1); // ISF (mg/dL/U) / CR (g/U) = CSF (mg/dL/g) // use profile.sens instead of autosens-adjusted sens to avoid counteracting // autosens meal insulin dosing adjustmenst when sensitive/resistant @@ -334,8 +334,12 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //if (meal_data.mealCOB * 3 > meal_data.carbs) { } // calculate peak deviation in last hour, and slope from that to current deviation - var minDeviationSlope = round(meal_data.minDeviationSlope,2); - //console.error(minDeviationSlope); + var slopeFromMaxDeviation = round(meal_data.slopeFromMaxDeviation,2); + // calculate lowest deviation in last hour, and slope from that to current deviation + var slopeFromMinDeviation = round(meal_data.slopeFromMinDeviation,2); + // assume deviations will drop back down at least at 1/3 the rate they ramped up + var slopeFromDeviations = Math.min(slopeFromMaxDeviation,-slopeFromMinDeviation/3); + //console.error(slopeFromMaxDeviation); aci = 10; //5m data points = g * (1U/10g) * (40mg/dL/1U) / (mg/dL/5m) @@ -393,17 +397,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //process.stderr.write(round(predCI,1)+"+"+round(remainingCI,1)+" "); COBpredBG = COBpredBGs[COBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predCI + remainingCI; aCOBpredBG = aCOBpredBGs[aCOBpredBGs.length-1] + predBGI + Math.min(0,predDev) + predACI; - // for UAMpredBGs, predicted carb impact drops at minDeviationSlope - // calculate predicted CI from UAM based on minDeviationSlope - predUCIslope = Math.max(0, uci + ( UAMpredBGs.length*minDeviationSlope ) ); - // if minDeviationSlope is too flat, predicted deviation impact drops linearly from + // for UAMpredBGs, predicted carb impact drops at slopeFromDeviations + // calculate predicted CI from UAM based on slopeFromDeviations + predUCIslope = Math.max(0, uci + ( UAMpredBGs.length*slopeFromDeviations ) ); + // if slopeFromDeviations is too flat, predicted deviation impact drops linearly from // current deviation down to zero over 3h (data points every 5m) predUCImax = Math.max(0, uci * ( 1 - UAMpredBGs.length/Math.max(3*60/5,1) ) ); //console.error(predUCIslope, predUCImax); // predicted CI from UAM is the lesser of CI based on deviationSlope or DIA predUCI = Math.min(predUCIslope, predUCImax); if(predUCI>0) { - //console.error(UAMpredBGs.length,minDeviationSlope, predUCI); + //console.error(UAMpredBGs.length,slopeFromDeviations, predUCI); UAMduration=round((UAMpredBGs.length+1)*5/60,1); } UAMpredBG = UAMpredBGs[UAMpredBGs.length-1] + predBGI + Math.min(0, predDev) + predUCI; diff --git a/lib/meal/total.js b/lib/meal/total.js index b1596e21a..c4fca109d 100644 --- a/lib/meal/total.js +++ b/lib/meal/total.js @@ -68,7 +68,7 @@ function recentCarbs(opts, time) { // set mealTime to 6h ago for Deviation calculations COB_inputs.mealTime = time.getTime() - 6 * 60 * 60 * 1000; var c = calcMealCOB(COB_inputs); - //console.error(c.currentDeviation, c.minDeviationSlope); + //console.error(c.currentDeviation, c.slopeFromMaxDeviation); // set a hard upper limit on COB to mitigate impact of erroneous or malicious carb entry mealCOB = Math.min( profile.maxCOB, mealCOB ); @@ -89,7 +89,9 @@ function recentCarbs(opts, time) { , mealCOB: Math.round( mealCOB ) , currentDeviation: Math.round( c.currentDeviation * 100 ) / 100 , maxDeviation: Math.round( c.maxDeviation * 100 ) / 100 - , minDeviationSlope: Math.round( c.minDeviationSlope * 1000 ) / 1000 + , minDeviation: Math.round( c.minDeviation * 100 ) / 100 + , slopeFromMaxDeviation: Math.round( c.slopeFromMaxDeviation * 1000 ) / 1000 + , slopeFromMinDeviation: Math.round( c.slopeFromMinDeviation * 1000 ) / 1000 }; } From 0c9cc1c39e1cbc708eedebe1c5fe03f1e59127d6 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 20 Sep 2017 17:13:49 -0700 Subject: [PATCH 085/215] proceed to enact and set clock if pumphistory-zoned is in the future (#652) --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 157b5eaf8..c5479cba3 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -483,7 +483,7 @@ function refresh_pumphistory_and_enact { setglucosetimestamp if ((find monitor/ -newer monitor/pumphistory-zoned.json | grep -q glucose.json && echo -n "glucose.json newer than pumphistory. ") \ || (find enact/ -newer monitor/pumphistory-zoned.json | grep -q enacted.json && echo -n "enacted.json newer than pumphistory. ") \ - || (! find monitor/ -mmin -5 | grep -q pumphistory-zoned && echo -n "pumphistory more than 5m old. ") ); then + || ((! find monitor/ -mmin -5 | grep -q pumphistory-zoned || ! find monitor/ -mmin +0 | grep -q pumphistory-zoned) && echo -n "pumphistory more than 5m old. ") ); then (echo -n ": " && gather && enact ) else echo Pumphistory less than 5m old From 0c7623524b37cebe482233b2ea5f42388eea1de9 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 20 Sep 2017 17:14:33 -0700 Subject: [PATCH 086/215] calculate autosens ratio with both 8h and 24h of data (#653) * calculate autosens as lowestRatio of 8h and 24h lookbacks * always exclude the first 45m after each carb entry from autosens * print out which ratio and ISF we're using * don't exclude as UAM until IOB > 2 * basal --- bin/oref0-detect-sensitivity.js | 17 ++++++++++++++++- lib/determine-basal/autosens.js | 22 +++++++++++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/bin/oref0-detect-sensitivity.js b/bin/oref0-detect-sensitivity.js index 7d3a511d9..7f9ccf218 100755 --- a/bin/oref0-detect-sensitivity.js +++ b/bin/oref0-detect-sensitivity.js @@ -88,9 +88,24 @@ if (!module.parent) { , basalprofile: basalprofile //, clock: clock_data }; + // calculate sensitivity using 8h of non-exluded data + detection_inputs.deviations = 96; detect(detection_inputs); + ratio8h = ratio; + newisf8h = newisf; + // calculate sensitivity using all non-exluded data (up to 24h) + detection_inputs.deviations = 288; + detect(detection_inputs); + ratio24h = ratio; + newisf24h = newisf; + if ( ratio8h < ratio24h ) { + console.error("Using 8h autosens ratio of",ratio8h,"(ISF",newisf8h+")"); + } else { + console.error("Using 24h autosens ratio of",ratio24h,"(ISF",newisf24h+")"); + } + var lowestRatio = Math.min(ratio8h, ratio24h); var sensAdj = { - "ratio": ratio + "ratio": lowestRatio } return console.log(JSON.stringify(sensAdj)); diff --git a/lib/determine-basal/autosens.js b/lib/determine-basal/autosens.js index 1dc1012f9..30d5a8c99 100644 --- a/lib/determine-basal/autosens.js +++ b/lib/determine-basal/autosens.js @@ -123,6 +123,7 @@ function detectSensitivity(inputs) { var uam = 0; // unannounced meal var mealCOB = 0; var mealCarbs = 0; + var mealStartCounter = 999; var type=""; //console.error(bucketed_data); for (var i=3; i < bucketed_data.length; ++i) { @@ -188,13 +189,11 @@ function detectSensitivity(inputs) { absorbed = ci * profile.carb_ratio / sens; mealCOB = Math.max(0, mealCOB-absorbed); } - // Store the COB, and use it as the starting point for the next data point. - // If mealCOB is zero but all deviations since hitting COB=0 are positive, assign those data points to CSFGlucoseData - // Once deviations go negative for at least one data point after COB=0, we can use the rest of the data to tune ISF or basals + // If mealCOB is zero but all deviations since hitting COB=0 are positive, exclude from autosens //console.error(mealCOB, absorbing, mealCarbs); if (mealCOB > 0 || absorbing || mealCarbs > 0) { - if (deviation > 0) { + if (deviation > 0 ) { absorbing = 1; } else { absorbing = 0; @@ -206,9 +205,11 @@ function detectSensitivity(inputs) { //console.error(type); if ( type != "csf" ) { process.stderr.write("g("); + mealStartCounter = 0; //glucoseDatum.mealAbsorption = "start"; //console.error(glucoseDatum.mealAbsorption,"carb absorption"); } + mealStartCounter++; type="csf"; glucoseDatum.mealCarbs = mealCarbs; //if (i == 0) { glucoseDatum.mealAbsorption = "end"; } @@ -222,7 +223,10 @@ function detectSensitivity(inputs) { } currentBasal = iob_inputs.profile.current_basal; - if (iob.iob > currentBasal || uam) { + // always exclude the first 45m after each carb entry + //if (iob.iob > currentBasal || uam ) { + if (iob.iob > 2 * currentBasal || uam || mealStartCounter < 9 ) { + mealStartCounter++; if (deviation > 0) { uam = 1; } else { @@ -233,6 +237,7 @@ function detectSensitivity(inputs) { //glucoseDatum.uamAbsorption = "start"; //console.error(glucoseDatum.uamAbsorption,"uannnounced meal absorption"); } + //console.error(mealStartCounter); type="uam"; } else { if ( type === "uam" ) { @@ -262,8 +267,10 @@ function detectSensitivity(inputs) { process.stderr.write("x"); //console.error(bgTime); } + var lookback = inputs.deviations; + if (!lookback) { lookback = 96; } // only keep the last 96 non-excluded data points (8h+ for any exclusions) - if (deviations.length > 96) { + if (deviations.length > lookback) { deviations.shift(); } } @@ -327,7 +334,8 @@ function detectSensitivity(inputs) { //console.error("Basal adjustment "+basalOff.toFixed(2)+"U/hr"); //console.error("Ratio: "+ratio*100+"%: new ISF: "+newisf.toFixed(1)+"mg/dL/U"); var output = { - "ratio": ratio + "ratio": ratio, + "newisf": newisf } return output; } From 14e6a29aefd7ced4713662f5b4f5bf0811d49bea Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 21 Sep 2017 15:38:51 -0700 Subject: [PATCH 087/215] disable SMB if predicted BG drops below threshold (#661) * don't set temp first if temp duration >20m * echo -n * only refresh pumphistory (twice) if it's more than 30m old * disable SMB if minGuardBG projected below threshold * better ordering --- bin/oref0-pump-loop.sh | 8 +++++--- lib/determine-basal/determine-basal.js | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index c5479cba3..93ff429a1 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -430,9 +430,9 @@ function refresh_old_pumphistory_enact { || ( echo -n "Old pumphistory: " && gather && enact ) } -# refresh pumphistory if it's more than 15m old, but don't enact +# refresh pumphistory if it's more than 30m old, but don't enact function refresh_old_pumphistory { - find monitor/ -mmin -15 -size +100c | grep -q pumphistory-zoned \ + find monitor/ -mmin -30 -size +100c | grep -q pumphistory-zoned \ || ( echo -n "Old pumphistory, waiting for $upto30s seconds of silence: " && wait_for_silence $upto30s && gather ) } @@ -455,7 +455,9 @@ function refresh_smb_temp_and_enact { setglucosetimestamp # only smb_enact_temp if we haven't successfully completed a pump_loop recently # (no point in enacting a temp that's going to get changed after we see our last SMB) - if ( find monitor/ -mmin +10 | grep -q monitor/pump_loop_completed ); then + if (cat monitor/temp_basal.json | json -c "this.duration > 20" | grep -q duration); then + echo -n "Temp duration >20m. " + elif ( find monitor/ -mmin +10 | grep -q monitor/pump_loop_completed ); then echo "pump_loop_completed more than 10m ago: setting temp before refreshing pumphistory. " smb_enact_temp else diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 312159834..c579b1c6f 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -358,6 +358,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var minIOBPredBG = 999; var minCOBPredBG = 999; var minUAMPredBG = 999; + var minGuardBG = 999; var minPredBG; var avgPredBG; var IOBpredBG = eventualBG; @@ -417,6 +418,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if ( COBpredBGs.length < 48) { COBpredBGs.push(COBpredBG); } if ( aCOBpredBGs.length < 48) { aCOBpredBGs.push(aCOBpredBG); } if ( UAMpredBGs.length < 48) { UAMpredBGs.push(UAMpredBG); } + // calculate minGuardBG without a wait from COB if available, or UAM, or IOB predBGs + if (cid || remainingCIpeak > 0) { + if ( COBpredBG < minGuardBG ) { minGuardBG = round(COBpredBG); } + } else if ( enableUAM ) { + if ( UAMpredBG < minGuardBG ) { minGuardBG = round(UAMpredBG); } + } else { + if ( IOBpredBG < minIOBPredBG ) { minIOBPredBG = round(IOBpredBG); } + } // wait 90m before setting minIOBPredBG if ( IOBpredBGs.length > 18 && (IOBpredBG < minIOBPredBG) ) { minIOBPredBG = round(IOBpredBG); } if ( IOBpredBG > maxIOBPredBG ) { maxIOBPredBG = IOBpredBG; } @@ -562,7 +571,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ rT.COB=meal_data.mealCOB; rT.IOB=iob_data.iob; - rT.reason="COB: " + meal_data.mealCOB + ", Dev: " + deviation + ", BGI: " + bgi + ", ISF: " + convert_bg(sens, profile) + ", Target: " + convert_bg(target_bg, profile) + ", minPredBG " + convert_bg(minPredBG, profile) + ", IOBpredBG " + convert_bg(lastIOBpredBG, profile); + rT.reason="COB: " + meal_data.mealCOB + ", Dev: " + deviation + ", BGI: " + bgi + ", ISF: " + convert_bg(sens, profile) + ", Target: " + convert_bg(target_bg, profile) + ", minPredBG " + convert_bg(minPredBG, profile) + ", minGuardBG " + convert_bg(minGuardBG, profile) + ", IOBpredBG " + convert_bg(lastIOBpredBG, profile); if (lastCOBpredBG > 0) { rT.reason += ", COBpredBG " + convert_bg(lastCOBpredBG, profile); } @@ -591,6 +600,11 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } } + if (enableSMB && minGuardBG < threshold) { + console.error("minGuardBG",minGuardBG,"projected below",threshold,"- disabling SMB"); + enableSMB = false; + } + console.error("BG projected to remain above",min_bg,"for",minutesAboveMinBG,"minutes"); // include at least minutesAboveMinBG worth of zero temps in calculating carbsReq // always include at least 30m worth of zero temp (carbs to 80, low temp up to target) From 901163d7eb24559c589c1fa8c6376191be095fae Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 21 Sep 2017 16:58:06 -0700 Subject: [PATCH 088/215] Refresh pumphistory before setting temps and after SMB/enact (#663) * don't set temp first if temp duration >20m * echo -n * only refresh pumphistory (twice) if it's more than 30m old * don't print enact/smb-suggested.json * if pump is suspended, return false * wait for bolus to complete and refresh pumphistory after SMB * only refresh after SMB/enact; wait_for_silence 10 if bolusing * syntax * gather has a bolusing check; no need for a full smb_verify_status * check for recent bolused.json instead * make SMB model failure explicit * echo -n * 10s is too short for a 0.8U SMB: try a third time after 20s more --- bin/oref0-pump-loop.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 93ff429a1..67f09d5af 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -63,6 +63,7 @@ smb_main() { fi ) \ && ( refresh_profile; refresh_pumphistory_24h; true ) \ + && refresh_after_bolus_or_enact \ && echo Completed supermicrobolus pump-loop at $(date): \ && touch monitor/pump_loop_completed -r monitor/pump_loop_enacted \ && echo \ @@ -204,13 +205,14 @@ function smb_verify_status { echo -n "Pump suspended; " unsuspend_if_no_temp gather + false fi } function smb_bolus { # Verify that the suggested.json is less than 5 minutes old # and administer the supermicrobolus - find enact/ -mmin -5 | grep smb-suggested.json \ + find enact/ -mmin -5 | grep smb-suggested.json > /dev/null \ && if (grep -q '"units":' enact/smb-suggested.json); then openaps report invoke enact/bolused.json 2>&1 >/dev/null | tail -1 \ && echo -n "enact/bolused.json: " && cat enact/bolused.json | jq -C -c . \ @@ -219,6 +221,15 @@ function smb_bolus { echo "No bolus needed (yet)" fi } + +function refresh_after_bolus_or_enact { + if (find enact/ -mmin -2 -size +5c | grep -q bolused.json || (cat monitor/temp_basal.json | json -c "this.duration > 28" | grep -q duration)); then + gather || ( wait_for_silence 10 && gather ) || ( wait_for_silence 20 && gather ) + true + fi + +} + function unsuspend_if_no_temp { # If temp basal duration is zero, unsuspend pump if (cat monitor/temp_basal.json | json -c "this.duration == 0" | grep -q duration); then From 1ce5d705114f5b9f8cc9787303aabe78cb956730 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 21 Sep 2017 17:50:49 -0700 Subject: [PATCH 089/215] autotune/autosens on by default; don't ask about ~/myopenaps (#664) * enable autosens and autotune by default * always use myopenaps for directory name unless specified as CLI option --- bin/oref0-setup.sh | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index b69815161..415944f69 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -146,17 +146,9 @@ if [[ -z "$DIR" || -z "$serial" ]]; then exit fi echo - echo -e "\e[1mWhat would you like to call your loop directory?\e[0m" - echo - echo "To use myopenaps, the recommended name, hit enter. If you choose to enter a different name here," - echo "then you will need to remember to substitute that other name in other areas of the docs" - echo "where the myopenaps directory is involved. Type in a directory name and/or just hit enter:" - read -r - DIR=$REPLY if [[ -z $DIR ]]; then DIR="myopenaps" fi - echocolor "Ok, $DIR it is." directory="$(readlink -m $DIR)" echo read -p "What is your pump serial number (numbers only)? " -r @@ -301,23 +293,23 @@ if [[ -z "$DIR" || -z "$serial" ]]; then echo fi - read -p "Enable automatic sensitivity adjustment? y/[N] " -r - if [[ $REPLY =~ ^[Yy]$ ]]; then - ENABLE+=" autosens " - echocolor "Ok, autosens will be enabled." + read -p "Enable automatic sensitivity adjustment? [Y]/n " -r + if [[ $REPLY =~ ^[Nn]$ ]]; then + echocolor "Ok, no autosens." echo else - echocolor "Ok, no autosens." + ENABLE+=" autosens " + echocolor "Ok, autosens will be enabled." echo fi - read -p "Enable autotuning of basals and ratios? y/[N] " -r - if [[ $REPLY =~ ^[Yy]$ ]]; then - ENABLE+=" autotune " - echocolor "Ok, autotune will be enabled. It will run around midnight." + read -p "Enable autotuning of basals and ratios? [Y]/n " -r + if [[ $REPLY =~ ^[Nn]$ ]]; then + echocolor "Ok, no autotune." echo else - echocolor "Ok, no autotune." + ENABLE+=" autotune " + echocolor "Ok, autotune will be enabled. It will run around midnight." echo fi @@ -903,8 +895,6 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then fi # configure supermicrobolus if enabled - # WARNING: supermicrobolus mode is not yet documented or ready for general testing - # It should only be tested with a disconnected pump not administering insulin. # If you aren't sure what you're doing, *DO NOT* enable this. # If you ignore this warning, it *WILL* administer extra post-meal insulin, which may cause low blood sugar. if [[ $ENABLE =~ microbolus ]]; then From 68747885af1790cd3e4a3c893711a07723d87255 Mon Sep 17 00:00:00 2001 From: jaylagorio Date: Sat, 23 Sep 2017 16:42:48 -0400 Subject: [PATCH 090/215] Update oref0-setup.sh (#666) --- bin/oref0-setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 415944f69..c1bcad870 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -964,6 +964,8 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then (crontab -l; crontab -l | grep -q "killall -g --older-than 30m oref0" || echo '* * * * * ( killall -g --older-than 30m openaps; killall -g --older-than 30m oref0-pump-loop; killall -g --older-than 30m openaps-report )') | crontab - # kill pump-loop after 5 minutes of not writing to pump-loop.log (crontab -l; crontab -l | grep -q "killall -g --older-than 5m oref0" || echo '* * * * * find /var/log/openaps/pump-loop.log -mmin +5 | grep pump && ( killall -g --older-than 5m openaps; killall -g --older-than 5m oref0-pump-loop; killall -g --older-than 5m openaps-report )') | crontab - + # remove pump_loop_completed on reboot so mmtune runs immediately on reboot + (crontab -l; crontab -l | grep -q "rm $directory/monitor/pump_loop_completed" || echo "@reboot rm $directory/monitor/pump_loop_completed") | crontab - if [[ ${CGM,,} =~ "shareble" || ${CGM,,} =~ "g4-upload" ]]; then (crontab -l; crontab -l | grep -q "cd $directory-cgm-loop && ps aux | grep -v grep | grep -q 'openaps monitor-cgm'" || echo "* * * * * cd $directory-cgm-loop && ps aux | grep -v grep | grep -q 'openaps monitor-cgm' || ( date; openaps monitor-cgm) | tee -a /var/log/openaps/cgm-loop.log; cp -up monitor/glucose-raw-merge.json $directory/cgm/glucose.json ; cp -up $directory/cgm/glucose.json $directory/monitor/glucose.json") | crontab - elif [[ ${CGM,,} =~ "xdrip" ]]; then From c1f353fbed3b9674ebf9681d41c856239c4ebe24 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 23 Sep 2017 22:01:17 -0700 Subject: [PATCH 091/215] more explicit CATimeAdjustment; extend remainingCATimeMin for >90g --- lib/determine-basal/determine-basal.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index d3faca369..17e407043 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -296,22 +296,25 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // ISF (mg/dL/U) / CR (g/U) = CSF (mg/dL/g) // use profile.sens instead of autosens-adjusted sens to avoid counteracting // autosens meal insulin dosing adjustmenst when sensitive/resistant - var csf = profile.sens / profile.carb_ratio + var csf = profile.sens / profile.carb_ratio; // set meal_carbimpact high enough to absorb all meal carbs over 6 hours // total_impact (mg/dL) = CSF (mg/dL/g) * carbs (g) //console.error(csf * meal_data.carbs); // meal_carbimpact (mg/dL/5m) = CSF (mg/dL/g) * carbs (g) / 6 (h) * (1h/60m) * 5 (m/5m) * 2 (for linear decay) //var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1) - // assume that all carbs will absorb over 4 more hours w/ normal targets - var remainingCATime = 4; + var remainingCATimeMin = 3; // h; before carb absorption starts + var remainingCATimeMax = 5; // h; just before carb absorption ends + var carbAbsorptionRate = 30; // g/h; maximum rate to assume carbs will absorb if no CI observed + var remainingCATime; if (meal_data.carbs) { - // number of hours to adjust remainingCATime. COB=carbs -> -1, COB=0.5*carbs -> 0 - fractionCOBAbsorbed = round(( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs,2); - remainingCATimeAdjustment = fractionCOBAbsorbed*2 - 1; - remainingCATime += remainingCATimeAdjustment; + // if carbs * carbAbsorptionRate > remainingCATimeMin, raise it + // so <= 90g is assumed to take 3h, and 120g=4h + remainingCATimeMin = Math.max(remainingCATimeMin, meal_data.carbs/carbAbsorptionRate); + fractionCOBAbsorbed = ( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs; + remainingCATime = remainingCATimeMin*(1-fractionCOBAbsorbed) + remainingCATimeMax*fractionCOBAbsorbed; remainingCATime = round(remainingCATime,1); //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) - console.error("Adjusting remainingCATime to",remainingCATime,"h based on",fractionCOBAbsorbed*100+"% carb absorption"); + console.error("Adjusting remainingCATime to",remainingCATime,"h based on",round(fractionCOBAbsorbed*100)+"% carb absorption"); } // calculate the number of carbs absorbed over remainingCATime hours at current CI @@ -354,7 +357,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } acid = Math.max(0, meal_data.mealCOB * csf / aci ); // duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay) - console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (2h peak):",round(remainingCIpeak,1),"mg/dL per 5m"); + console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (~2h peak):",round(remainingCIpeak,1),"mg/dL per 5m"); console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours"); var minIOBPredBG = 999; var minCOBPredBG = 999; From af0ef3a37d9f066ab8b9c6bd7c94821ed48fa8d8 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 23 Sep 2017 22:02:01 -0700 Subject: [PATCH 092/215] allow SMBs to consider COBPredBGs > 400 --- lib/determine-basal/determine-basal.js | 27 ++++++++++++-------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 17e407043..3c50a99dd 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -508,18 +508,15 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ minPredBG = round(minIOBPredBG); var fractionCarbsLeft = meal_data.mealCOB/meal_data.carbs; - // if we have COB and UAM is enabled, average all three - if ( minUAMPredBG < 400 && minCOBPredBG < 400 ) { + // if we have COB and UAM is enabled, average both + if ( minUAMPredBG < 999 && minCOBPredBG < 999 ) { // weight COBpredBG vs. UAMpredBG based on how many carbs remain as COB - avgPredBG = round( (IOBpredBG/3 + (1-fractionCarbsLeft)*UAMpredBG*2/3 + fractionCarbsLeft*COBpredBG*2/3) ); + avgPredBG = round( (1-fractionCarbsLeft)*UAMpredBG + fractionCarbsLeft*COBpredBG ); // if UAM is disabled, average IOB and COB - } else if ( minCOBPredBG < 400 ) { + } else if ( minCOBPredBG < 999 ) { avgPredBG = round( (IOBpredBG + COBpredBG)/2 ); - // if carbs are expired, use IOB instead of COB - } else if ( meal_data.carbs && minUAMPredBG < 400 ) { - avgPredBG = round( (2*IOBpredBG + UAMpredBG)/3 ); - // in pure UAM mode, just average IOB and UAM - } else if ( minUAMPredBG < 400 ) { + // if we have UAM but no COB, average IOB and UAM + } else if ( minUAMPredBG < 999 ) { avgPredBG = round( (IOBpredBG + UAMpredBG)/2 ); } else { avgPredBG = round( IOBpredBG ); @@ -528,17 +525,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // if any carbs have been entered recently if (meal_data.carbs) { // average the minIOBPredBG and minUAMPredBG if available - if ( minUAMPredBG < 400 ) { + if ( minUAMPredBG < 999 ) { avgMinPredBG = round( (minIOBPredBG+minUAMPredBG)/2 ); } else { avgMinPredBG = minIOBPredBG; } // if UAM is disabled, use max of minIOBPredBG, minCOBPredBG - if ( ! enableUAM && minCOBPredBG < 400 ) { + if ( ! enableUAM && minCOBPredBG < 999 ) { minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG)); // if we have COB, use minCOBPredBG, or blendedMinPredBG if it's higher - } else if ( minCOBPredBG < 400 ) { + } else if ( minCOBPredBG < 999 ) { // calculate blendedMinPredBG based on how many carbs remain as COB blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*avgMinPredBG; // if blendedMinPredBG > minCOBPredBG, use that instead @@ -556,10 +553,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ minPredBG = Math.min( minPredBG, avgPredBG ); process.stderr.write("minPredBG: "+minPredBG+" minIOBPredBG: "+minIOBPredBG); - if (minCOBPredBG < 400) { + if (minCOBPredBG < 999) { process.stderr.write(" minCOBPredBG: "+minCOBPredBG); } - if (minUAMPredBG < 400) { + if (minUAMPredBG < 999) { process.stderr.write(" minUAMPredBG: "+minUAMPredBG); } console.error(" avgPredBG:",avgPredBG,"COB:",meal_data.mealCOB,"carbs:",meal_data.carbs); @@ -569,7 +566,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ minPredBG = Math.min(minPredBG, maxCOBPredBG); } // set snoozeBG to minPredBG if it's higher - if (minPredBG < 400) { + if (minPredBG < 999) { snoozeBG = round(Math.max(snoozeBG,minPredBG)); } rT.snoozeBG = snoozeBG; From ec80ac202611f1ecfab7e7794a149371f67f1e8e Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 23 Sep 2017 22:02:42 -0700 Subject: [PATCH 093/215] check max_iob against net IOB, not just basaliob --- lib/determine-basal/determine-basal.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 3c50a99dd..ace58ae47 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -804,15 +804,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // eventual BG is at/above target (or bolus snooze disabled for SMB) // if iob is over max, just cancel any temps - var basaliob; if (iob_data.basaliob) { basaliob = iob_data.basaliob; } else { basaliob = iob_data.iob - iob_data.bolussnooze; } // if we're not here because of SMB, eventual BG is at/above target if (! (microBolusAllowed && rT.COB)) { rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " >= " + convert_bg(max_bg, profile) + ", "; } - if (basaliob > max_iob) { - rT.reason += "basaliob " + round(basaliob,2) + " > max_iob " + max_iob; + if (iob_data.iob > max_iob) { + rT.reason += "IOB " + round(iob_data.iob,2) + " > max_iob " + max_iob; if (currenttemp.duration > 15 && (round_basal(basal, profile) === round_basal(currenttemp.rate, profile))) { rT.reason += ", temp " + currenttemp.rate + " ~ req " + basal + "U/hr. "; return rT; @@ -833,9 +832,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ insulinReq = newinsulinReq; } // if that would put us over max_iob, then reduce accordingly - if (insulinReq > max_iob-basaliob) { + if (insulinReq > max_iob-iob_data.iob) { rT.reason += "max_iob " + max_iob + ", "; - insulinReq = max_iob-basaliob; + insulinReq = max_iob-iob_data.iob; } // rate required to deliver insulinReq more insulin over 30m: From d0fc003e4a380b10b99146b29668d630b81816ab Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 23 Sep 2017 22:03:41 -0700 Subject: [PATCH 094/215] always SMB 1/2 of insulinReq --- lib/determine-basal/determine-basal.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index ace58ae47..e4f3b3a48 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -864,18 +864,8 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ console.error("profile.maxSMBBasalMinutes:",profile.maxSMBBasalMinutes,"profile.current_basal:",profile.current_basal); maxBolus = round( profile.current_basal * profile.maxSMBBasalMinutes / 60 ,1); } - // bolus 1/3 the insulinReq, up to maxBolus - microBolus = round(Math.min(insulinReq/3,maxBolus),1); - // if IOB doesn't cover COB, microBolus 1/2 the insulinReq - // (or enough insulin to cover COB, or maxBolus, whichever is smallest) - if ( iob_data.iob < mealInsulinReq ) { - initialMealInsulinReq = round(mealInsulinReq-iob_data.iob,1); - console.error("IOB",iob_data.iob,"< COB",meal_data.mealCOB+"; insulinReq/2 =",insulinReq/2+"; initialMealInsulinReq =",initialMealInsulinReq); - if (initialMealInsulinReq > microBolus) { - microBolus = round(Math.min(insulinReq/2,maxBolus,initialMealInsulinReq),1); - } - } - + // bolus 1/2 the insulinReq, up to maxBolus + microBolus = round(Math.min(insulinReq/2,maxBolus),1); // calculate a long enough zero temp to eventually correct back up to target var smbTarget = target_bg; var worstCaseInsulinReq = (smbTarget - (naive_eventualBG + minIOBPredBG)/2 ) / sens; From 266a3b5e3a0bdaaf53621b6aaf948c29f717d00f Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 23 Sep 2017 22:13:20 -0700 Subject: [PATCH 095/215] remainingCATimeMax = 6 --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index e4f3b3a48..b15c66e4f 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -303,7 +303,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // meal_carbimpact (mg/dL/5m) = CSF (mg/dL/g) * carbs (g) / 6 (h) * (1h/60m) * 5 (m/5m) * 2 (for linear decay) //var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1) var remainingCATimeMin = 3; // h; before carb absorption starts - var remainingCATimeMax = 5; // h; just before carb absorption ends + var remainingCATimeMax = 6; // h; just before carb absorption ends var carbAbsorptionRate = 30; // g/h; maximum rate to assume carbs will absorb if no CI observed var remainingCATime; if (meal_data.carbs) { From ed7257d4317c2ffa37a3562ce2f7c9dd2534210b Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 23 Sep 2017 22:17:26 -0700 Subject: [PATCH 096/215] start setting minIOBPredBG at 70m for insulinPeakTime of 55m --- lib/determine-basal/determine-basal.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index b15c66e4f..4332a4d5f 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -423,18 +423,32 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if ( aCOBpredBGs.length < 48) { aCOBpredBGs.push(aCOBpredBG); } if ( UAMpredBGs.length < 48) { UAMpredBGs.push(UAMpredBG); } // calculate minGuardBG without a wait from COB if available, or UAM, or IOB predBGs - if (cid || remainingCIpeak > 0) { + if ( (cid || remainingCIpeak > 0) && fractionCOBAbsorbed < 0.75 ) { if ( COBpredBG < minGuardBG ) { minGuardBG = round(COBpredBG); } } else if ( enableUAM ) { if ( UAMpredBG < minGuardBG ) { minGuardBG = round(UAMpredBG); } } else { if ( IOBpredBG < minIOBPredBG ) { minIOBPredBG = round(IOBpredBG); } } - // wait 90m before setting minIOBPredBG - if ( IOBpredBGs.length > 18 && (IOBpredBG < minIOBPredBG) ) { minIOBPredBG = round(IOBpredBG); } + + // set minPredBGs starting when currently-dosed insulin activity will peak + var insulinPeakTime = 75; + if ( profile.insulinPeakTime ) { + insulinPeakTime = profile.insulinPeakTime; + } + if ( profile.curve == "ultra-rapid" && !profile.useCustomPeakTime ) { + insulinPeakTime = 55; + } + // add 15m to allow for insluin delivery (SMBs or temps) + insulinPeakTime += 15; + var insulinPeak5m = (insulinPeakTime/60)*12; + //console.error(insulinPeakTime, insulinPeak5m, profile.insulinPeakTime, profile.curve); + + // wait 70-90m before setting minIOBPredBG + if ( IOBpredBGs.length > insulinPeak5m && (IOBpredBG < minIOBPredBG) ) { minIOBPredBG = round(IOBpredBG); } if ( IOBpredBG > maxIOBPredBG ) { maxIOBPredBG = IOBpredBG; } - // wait 90m before setting COB and 60m for UAM minPredBGs - if ( (cid || remainingCIpeak > 0) && COBpredBGs.length > 18 && (COBpredBG < minCOBPredBG) ) { minCOBPredBG = round(COBpredBG); } + // wait 70-90m before setting COB and 60m for UAM minPredBGs + if ( (cid || remainingCIpeak > 0) && COBpredBGs.length > insulinPeak5m && (COBpredBG < minCOBPredBG) ) { minCOBPredBG = round(COBpredBG); } if ( (cid || remainingCIpeak > 0) && COBpredBG > maxIOBPredBG ) { maxCOBPredBG = COBpredBG; } if ( enableUAM && UAMpredBGs.length > 12 && (UAMpredBG < minUAMPredBG) ) { minUAMPredBG = round(UAMpredBG); } if ( enableUAM && UAMpredBG > maxIOBPredBG ) { maxUAMPredBG = UAMpredBG; } From 8cbe050ef27b97401037e40b7b3102e03ef61432 Mon Sep 17 00:00:00 2001 From: Dana Lewis Date: Sat, 23 Sep 2017 22:24:42 -0700 Subject: [PATCH 097/215] x12 automation (#665) * 0.5.4 * Creating script entry for identifying x12 pump models * First attempt at scripting file copying and alias changes automatically for x12 pump models * Attempting to add to runagain and echo properly as list of options before running setup * Create settings.json * Create bg-targets-raw.json * Create selected-basal-profile.json * Revert "Attempting to add to runagain and echo properly as list of options before running setup" This reverts commit 34d0c2f1a9bd77fcc2dbb02e454346480f438e9a. * only apply the changes Dana wanted * syntax * move x12 automation before cron, and fix directories etc. * fix dashes to underscores * fix dashes to underscores * accept --pumpmodel * logic * remove bash comments from json file * it's basal_profile.json not selected_basal_profile.json * remove settings not used by oref0 * whitespace * default to zero basals so they have to be changed * prompt x12 users to edit their basal_profile.json * add newline * only display "pump model untested with SMB" for x12 pumps * don't ask about SMB for x12 pumps * only add pumpmodel to runagain if it is set --- bin/oref0-pump-loop.sh | 2 +- bin/oref0-setup.sh | 61 ++++++++++++++++++++++++----- lib/oref0-setup/basal_profile.json | 50 +++++++++++++++++++++++ lib/oref0-setup/bg_targets_raw.json | 30 ++++++++++++++ lib/oref0-setup/settings.json | 8 ++++ 5 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 lib/oref0-setup/basal_profile.json create mode 100644 lib/oref0-setup/bg_targets_raw.json create mode 100644 lib/oref0-setup/settings.json diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 67f09d5af..be74ee5a6 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -329,7 +329,7 @@ function preflight { echo -n "Preflight " # only 515, 522, 523, 715, 722, 723, 554, and 754 pump models have been tested with SMB ( openaps report invoke settings/model.json || openaps report invoke settings/model.json ) 2>&1 >/dev/null | tail -1 \ - && ( egrep -q "[57](15|22|23|54)" settings/model.json || (echo -n "error: pump model untested with SMB: "; false) ) \ + && ( egrep -q "[57](15|22|23|54)" settings/model.json || (grep 12 settings/model.json && echo -n "error: pump model untested with SMB: "; false) ) \ && echo -n "OK. " \ || ( echo -n "fail. "; false ) } diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index c1bcad870..9cee0f34e 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -58,6 +58,10 @@ case $i in radio_locale="${i#*=}" shift # past argument=value ;; + -pm=*|--pumpmodel=*) + pumpmodel="${i#*=}" + shift # past argument=value + ;; -t=*|--tty=*) ttyport="${i#*=}" shift # past argument=value @@ -151,10 +155,21 @@ if [[ -z "$DIR" || -z "$serial" ]]; then fi directory="$(readlink -m $DIR)" echo + read -p "What is your pump serial number (numbers only)? " -r serial=$REPLY echocolor "Ok, $serial it is." echo + + read -p "Do you have an x12 (i.e. 512 or 712) pump? y/[N] " -r + if [[ $REPLY =~ ^[Yy]$ ]]; then + pumpmodel=x12 + echocolor "Ok, you'll be using a 512 or 712 pump. Got it. " + echo + else + echocolor "You're using a different model pump. Got it." + fi + read -p "What kind of CGM are you using? (e.g., G4-upload, G4-local-only, G5, MDT, xdrip?) Note: G4-local-only will NOT upload BGs from a plugged in receiver to Nightscout: " -r CGM=$REPLY echocolor "Ok, $CGM it is." @@ -392,6 +407,10 @@ if [[ ${CGM,,} =~ "shareble" ]]; then fi echo echo -n "NS host $NIGHTSCOUT_HOST, " +if [[ ${pumpmodel,,} =~ "x12" ]]; then + echo -n "x12 pump, " +fi + if [[ -z "$ttyport" ]]; then echo -n Carelink else @@ -433,6 +452,9 @@ echo -n " --ns-host=$NIGHTSCOUT_HOST --api-secret=$API_SECRET" | tee -a $OREF0_R if [[ ! -z "$ttyport" ]]; then echo -n " --tty=$ttyport" | tee -a $OREF0_RUNAGAIN fi +if [[ ! -z "$pumpmodel" ]]; then + echo -n " --pumpmodel=$pumpmodel" | tee -a $OREF0_RUNAGAIN; +fi echo -n " --max_iob=$max_iob" | tee -a $OREF0_RUNAGAIN; if [[ ! -z "$max_daily_safety_multiplier" ]]; then echo -n " --max_daily_safety_multiplier=$max_daily_safety_multiplier" | tee -a $OREF0_RUNAGAIN @@ -894,16 +916,25 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then done fi - # configure supermicrobolus if enabled - # If you aren't sure what you're doing, *DO NOT* enable this. - # If you ignore this warning, it *WILL* administer extra post-meal insulin, which may cause low blood sugar. - if [[ $ENABLE =~ microbolus ]]; then - sudo apt-get -y install bc jq - cd $directory || die "Can't cd $directory" - for type in supermicrobolus; do - echo importing $type file - cat $HOME/src/oref0/lib/oref0-setup/$type.json | openaps import || die "Could not import $type.json" - done + if [[ ${pumpmodel,,} =~ "x12" ]]; then + echo "copying settings files for x12 pumps" + cp $HOME/src/oref0/lib/oref0-setup/bg_targets_raw.json $directory/settings/ && cp $HOME/src/oref0/lib/oref0-setup/basal_profile.json $directory/settings/ && cp $HOME/src/oref0/lib/oref0-setup/settings.json $directory/settings/ || die "Could not copy settings files for x12 pumps" + echo "getting ready to remove get-settings since this is an x12" + openaps alias remove get-settings || die "Could not remove get-settings" + echo "settings removed, getting ready to add x12 settings" + openaps alias add get-settings "report invoke settings/model.json settings/bg_targets.json settings/insulin_sensitivities_raw.json settings/insulin_sensitivities.json settings/carb_ratios.json settings/profile.json" || die "Could not add x12 settings" + else + # configure supermicrobolus if enabled + # If you aren't sure what you're doing, *DO NOT* enable this. + # If you ignore this warning, it *WILL* administer extra post-meal insulin, which may cause low blood sugar. + if [[ $ENABLE =~ microbolus ]]; then + sudo apt-get -y install bc jq + cd $directory || die "Can't cd $directory" + for type in supermicrobolus; do + echo importing $type file + cat $HOME/src/oref0/lib/oref0-setup/$type.json | openaps import || die "Could not import $type.json" + done + fi fi echo "Adding OpenAPS log shortcuts" @@ -1016,6 +1047,16 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then echo "To pair your G4 Share receiver, open its Settings, select Share, Forget Device (if previously paired), then turn sharing On" fi + if [[ ${pumpmodel,,} =~ "x12" ]]; then + echo + echo To complete your x12 pump setup, you must edit your basal_profile.json, + echo and may want to edit your settings.json and bg_targets_raw.json as well. + read -p "Press enter to begin editing basal_profile.json, and then press Ctrl-X when done." + nano $directory/settings/basal_profile.json + echo To edit your basal_profile.json again in the future, run: nano $directory/settings/basal_profile.json + echo To edit your settings.json to set maxBasal or DIA, run: nano $directory/settings/settings.json + echo To edit your bg_targets_raw.json to set targets, run: nano $directory/settings/bg_targets_raw.json + fi fi # from 'read -p "Continue? y/[N] " -r' after interactive setup is complete diff --git a/lib/oref0-setup/basal_profile.json b/lib/oref0-setup/basal_profile.json new file mode 100644 index 000000000..b9e18784e --- /dev/null +++ b/lib/oref0-setup/basal_profile.json @@ -0,0 +1,50 @@ +[ + { + "i": 0, + "start": "00:00:00", + "rate": 0, + "minutes": 0 + }, + { + "i": 1, + "start": "02:30:00", + "rate": 0, + "minutes": 150 + }, + { + "i": 2, + "start": "06:00:00", + "rate": 0, + "minutes": 360 + }, + { + "i": 3, + "start": "09:00:00", + "rate": 0, + "minutes": 600 + }, + { + "i": 4, + "start": "11:30:00", + "rate": 0, + "minutes": 690 + }, + { + "i": 5, + "start": "14:00:00", + "rate": 0, + "minutes": 840 + }, + { + "i": 6, + "start": "18:30:00", + "rate": 0, + "minutes": 1110 + }, + { + "i": 7, + "start": "23:00:00", + "rate": 0, + "minutes": 1380 + } +] diff --git a/lib/oref0-setup/bg_targets_raw.json b/lib/oref0-setup/bg_targets_raw.json new file mode 100644 index 000000000..b7c410929 --- /dev/null +++ b/lib/oref0-setup/bg_targets_raw.json @@ -0,0 +1,30 @@ +{ + "units": "mg/dL", + "targets": [ + { + "high": 120, + "start": "00:00:00", + "low": 110, + "offset": 0, + "i": 0, + "x": 0 + }, + { + "high": 110, + "start": "06:00:00", + "low": 110, + "offset": 360, + "i": 12, + "x": 1 + }, + { + "high": 120, + "start": "20:00:00", + "low": 110, + "offset": 1200, + "i": 40, + "x": 2 + } + ], + "first": 1 +} diff --git a/lib/oref0-setup/settings.json b/lib/oref0-setup/settings.json new file mode 100644 index 000000000..875328d7d --- /dev/null +++ b/lib/oref0-setup/settings.json @@ -0,0 +1,8 @@ +{ + "maxBasal": 1.5, + "temp_basal": { + "percent": 100, + "type": "Units/hour" + }, + "insulin_action_curve": 6 +} From c00311667e1c597630307e7b78ca8abd75b816d8 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 23 Sep 2017 23:20:37 -0700 Subject: [PATCH 098/215] remove old commented-out let-it-run code --- lib/determine-basal/determine-basal.js | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 4332a4d5f..6b1e9f32c 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -760,29 +760,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } } - /* - var minutes_running; - if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { - minutes_running = 30; - } else if (typeof currenttemp.minutesrunning !== 'undefined'){ - // If the time the current temp is running is not defined, use default request duration of 30 minutes. - minutes_running = currenttemp.minutesrunning; - } else { - minutes_running = 30 - currenttemp.duration; - } - - // if there is a low-temp running, and eventualBG would be below min_bg without it, let it run - if (round_basal(currenttemp.rate, profile) < round_basal(basal, profile) ) { - var lowtempimpact = (currenttemp.rate - basal) * ((30-minutes_running)/60) * sens; - var adjEventualBG = eventualBG + lowtempimpact; - // don't return early if microBolusAllowed etc. - if ( adjEventualBG < min_bg && ! (microBolusAllowed && enableSMB)) { - rT.reason += "letting low temp of " + currenttemp.rate + " run."; - return rT; - } - } - */ - // if eventual BG is above min but BG is falling faster than expected Delta if (minDelta < expectedDelta) { // if in SMB mode, don't cancel SMB zero temp From 4fdf0c22a9ed8fa539f28594752e0d2a39199a4a Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 23 Sep 2017 23:24:32 -0700 Subject: [PATCH 099/215] PLGS mode for minGuardBG < threshold --- lib/determine-basal/determine-basal.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 6b1e9f32c..1cce6896d 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -641,9 +641,13 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ rT.reason += "IOB "+iob_data.iob+" < " + round(-profile.current_basal*20/60,2); rT.reason += " and minDelta " + minDelta + " > " + "expectedDelta " + expectedDelta + "; "; } - // low glucose suspend mode: BG is < ~80 - else if (bg < threshold) { - rT.reason += "BG " + convert_bg(bg, profile) + "<" + convert_bg(threshold, profile); + // (predictive) low glucose suspend mode: BG is (projected to be) < ~80 + else if ( bg < threshold || minGuardBG < threshold ) { + if ( bg < threshold ) { + rT.reason += "BG " + convert_bg(bg, profile) + "<" + convert_bg(threshold, profile); + } else { + rT.reason += "minGuardBG " + convert_bg(minGuardBG, profile) + "<" + convert_bg(threshold, profile); + } if ((glucose_status.delta <= 0 && minDelta <= 0) || (glucose_status.delta < expectedDelta && minDelta < expectedDelta) || bg < 60 ) { // BG is still falling / rising slower than predicted if ( minDelta < expectedDelta ) { From bacd73cb2a87e2f5f1bc80f0394b26e383e2376e Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 23 Sep 2017 23:55:55 -0700 Subject: [PATCH 100/215] zero temp if minGuardBG < threshold regardless of delta --- lib/determine-basal/determine-basal.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 1cce6896d..c50010705 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -640,14 +640,13 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if (bg < threshold && iob_data.iob < -profile.current_basal*20/60 && minDelta > 0 && minDelta > expectedDelta) { rT.reason += "IOB "+iob_data.iob+" < " + round(-profile.current_basal*20/60,2); rT.reason += " and minDelta " + minDelta + " > " + "expectedDelta " + expectedDelta + "; "; - } - // (predictive) low glucose suspend mode: BG is (projected to be) < ~80 - else if ( bg < threshold || minGuardBG < threshold ) { - if ( bg < threshold ) { - rT.reason += "BG " + convert_bg(bg, profile) + "<" + convert_bg(threshold, profile); - } else { - rT.reason += "minGuardBG " + convert_bg(minGuardBG, profile) + "<" + convert_bg(threshold, profile); - } + // predictive low glucose suspend mode: BG is projected to be < threshold + } else if ( minGuardBG < threshold ) { + rT.reason += "minGuardBG " + convert_bg(minGuardBG, profile) + "<" + convert_bg(threshold, profile); + return tempBasalFunctions.setTempBasal(0, 30, profile, rT, currenttemp); + // low glucose suspend mode: BG is < ~80 + } else if ( bg < threshold || minGuardBG < threshold ) { + rT.reason += "BG " + convert_bg(bg, profile) + "<" + convert_bg(threshold, profile); if ((glucose_status.delta <= 0 && minDelta <= 0) || (glucose_status.delta < expectedDelta && minDelta < expectedDelta) || bg < 60 ) { // BG is still falling / rising slower than predicted if ( minDelta < expectedDelta ) { From b29b41ee4453e0b5feec9f9547b8a9930919040f Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 24 Sep 2017 00:04:29 -0700 Subject: [PATCH 101/215] add comment --- lib/determine-basal/determine-basal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index c50010705..58cab5d13 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -643,6 +643,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // predictive low glucose suspend mode: BG is projected to be < threshold } else if ( minGuardBG < threshold ) { rT.reason += "minGuardBG " + convert_bg(minGuardBG, profile) + "<" + convert_bg(threshold, profile); + // always set a 30m zero temp (oref0-pump-loop will let any longer SMB zero temp run) return tempBasalFunctions.setTempBasal(0, 30, profile, rT, currenttemp); // low glucose suspend mode: BG is < ~80 } else if ( bg < threshold || minGuardBG < threshold ) { From 4e3d0a0683e5caf11f9556eee4356ba891fae07c Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 24 Sep 2017 11:02:55 -0700 Subject: [PATCH 102/215] wait for bolus to complete and refresh pumphistory after SMB/enact (#667) * don't set temp first if temp duration >20m * echo -n * only refresh pumphistory (twice) if it's more than 30m old * don't print enact/smb-suggested.json * if pump is suspended, return false * wait for bolus to complete and refresh pumphistory after SMB * only refresh after SMB/enact; wait_for_silence 10 if bolusing * syntax * gather has a bolusing check; no need for a full smb_verify_status * check for recent bolused.json instead * make SMB model failure explicit * echo -n * 10s is too short for a 0.8U SMB: try a third time after 20s more * refresh_profile every 5m after a temp set, every 15m otherwise * print correct profileage * refresh_profile every 3m after temp/SMB --- bin/oref0-pump-loop.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index be74ee5a6..1222eea35 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -62,7 +62,7 @@ smb_main() { )) fi ) \ - && ( refresh_profile; refresh_pumphistory_24h; true ) \ + && ( refresh_profile 15; refresh_pumphistory_24h; true ) \ && refresh_after_bolus_or_enact \ && echo Completed supermicrobolus pump-loop at $(date): \ && touch monitor/pump_loop_completed -r monitor/pump_loop_enacted \ @@ -224,6 +224,8 @@ function smb_bolus { function refresh_after_bolus_or_enact { if (find enact/ -mmin -2 -size +5c | grep -q bolused.json || (cat monitor/temp_basal.json | json -c "this.duration > 28" | grep -q duration)); then + # refresh profile if >5m old to give SMB a chance to deliver + refresh_profile 3 gather || ( wait_for_silence 10 && gather ) || ( wait_for_silence 20 && gather ) true fi @@ -504,7 +506,12 @@ function refresh_pumphistory_and_enact { } function refresh_profile { - find settings/ -mmin -10 -size +5c | grep -q settings.json && echo Settings less than 10m old \ + if [ -z $1 ]; then + profileage=10 + else + profileage=$1 + fi + find settings/ -mmin -$profileage -size +5c | grep -q settings.json && echo Settings less than $profileage minutes old \ || (echo -n Settings refresh && openaps get-settings 2>/dev/null >/dev/null && echo ed) } From 0649d27f343fe928db8533299622ebdc63adf58a Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 24 Sep 2017 11:03:27 -0700 Subject: [PATCH 103/215] enable autosens and autotune by default (#669) From 32319a6eedae595dfa076bc276df0cbc792d67e9 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 24 Sep 2017 11:03:43 -0700 Subject: [PATCH 104/215] make sure another rig isn't also talking before proceeding to SMB (#670) --- bin/oref0-pump-loop.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 1222eea35..7a492f965 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -110,6 +110,7 @@ function smb_check_everything { && smb_enact_temp \ && if (grep -q '"units":' enact/smb-suggested.json); then ( smb_verify_suggested || smb_suggest ) \ + && wait_for_silence 1 \ && smb_verify_reservoir \ && smb_verify_status \ || ( echo Retrying SMB checks From 390888ca0d9878b809ddb82d396bd8f14631cf9a Mon Sep 17 00:00:00 2001 From: jaylagorio Date: Sun, 24 Sep 2017 17:01:03 -0400 Subject: [PATCH 105/215] Put pump_loop_completed in /tmp/ (#672) * Put pump_loop_completed in /tmp/ Changes the location of pump_loop_completed from $directory/monitor/ to /tmp/ so it disappears after reboot. * Update oref0-pump-loop.sh --- bin/oref0-pump-loop.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 7a492f965..216429e56 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -11,13 +11,13 @@ main() { && refresh_old_pumphistory_enact \ && refresh_old_pumphistory_24h \ && refresh_old_profile \ - && touch monitor/pump_loop_enacted -r monitor/glucose.json \ + && touch /tmp/pump_loop_enacted -r monitor/glucose.json \ && ( refresh_temp_and_enact || ( smb_verify_status && refresh_temp_and_enact ) ) \ && refresh_pumphistory_and_enact \ && refresh_profile \ && refresh_pumphistory_24h \ && echo Completed pump-loop at $(date) \ - && touch monitor/pump_loop_completed -r monitor/pump_loop_enacted \ + && touch /tmp/pump_loop_completed -r /tmp/pump_loop_enacted \ && echo); do if grep -q "percent" monitor/temp_basal.json; then @@ -44,12 +44,12 @@ smb_main() { && refresh_old_pumphistory_24h \ && refresh_old_pumphistory \ && refresh_old_profile \ - && touch monitor/pump_loop_enacted -r monitor/glucose.json \ + && touch /tmp/pump_loop_enacted -r monitor/glucose.json \ && refresh_smb_temp_and_enact \ && ( smb_check_everything \ && if (grep -q '"units":' enact/smb-suggested.json); then ( smb_bolus && \ - touch monitor/pump_loop_completed -r monitor/pump_loop_enacted \ + touch /tmp/pump_loop_completed -r /tmp/pump_loop_enacted \ ) \ || ( smb_old_temp && ( \ echo "Falling back to normal pump-loop" \ @@ -65,7 +65,7 @@ smb_main() { && ( refresh_profile 15; refresh_pumphistory_24h; true ) \ && refresh_after_bolus_or_enact \ && echo Completed supermicrobolus pump-loop at $(date): \ - && touch monitor/pump_loop_completed -r monitor/pump_loop_enacted \ + && touch /tmp/pump_loop_completed -r /tmp/pump_loop_enacted \ && echo \ ); then echo -n "SMB pump-loop failed. " @@ -364,7 +364,7 @@ function mmtune { } function maybe_mmtune { - if ( find monitor/ -mmin -15 | egrep -q "pump_loop_completed" ); then + if ( find /tmp/ -mmin -15 | egrep -q "pump_loop_completed" ); then # mmtune ~ 25% of the time [[ $(( ( RANDOM % 100 ) )) > 75 ]] \ && echo "Waiting for 40s silence before mmtuning" \ @@ -471,7 +471,7 @@ function refresh_smb_temp_and_enact { # (no point in enacting a temp that's going to get changed after we see our last SMB) if (cat monitor/temp_basal.json | json -c "this.duration > 20" | grep -q duration); then echo -n "Temp duration >20m. " - elif ( find monitor/ -mmin +10 | grep -q monitor/pump_loop_completed ); then + elif ( find /tmp/ -mmin +10 | grep -q /tmp/pump_loop_completed ); then echo "pump_loop_completed more than 10m ago: setting temp before refreshing pumphistory. " smb_enact_temp else @@ -524,9 +524,9 @@ function wait_for_bg { for i in `seq 1 24`; do # set mtime of monitor/glucose.json to the time of its most recent glucose value touch -d "$(date -R -d @$(jq .[0].date/1000 monitor/glucose.json))" monitor/glucose.json - if (! ls monitor/pump_loop_completed >/dev/null ); then + if (! ls /tmp/pump_loop_completed >/dev/null ); then break - elif (find monitor/ -newer monitor/pump_loop_completed | grep -q glucose.json); then + elif (find /tmp/ -newer /tmp/pump_loop_completed | grep -q glucose.json); then echo glucose.json newer than pump_loop_completed break else From 2989ea2dc6f0770bbdfed6a673ebe168c3dd6a14 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 24 Sep 2017 14:01:21 -0700 Subject: [PATCH 106/215] Revert "Update oref0-setup.sh (#666)" This reverts commit 68747885af1790cd3e4a3c893711a07723d87255. --- bin/oref0-setup.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 9cee0f34e..b6af15f74 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -995,8 +995,6 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then (crontab -l; crontab -l | grep -q "killall -g --older-than 30m oref0" || echo '* * * * * ( killall -g --older-than 30m openaps; killall -g --older-than 30m oref0-pump-loop; killall -g --older-than 30m openaps-report )') | crontab - # kill pump-loop after 5 minutes of not writing to pump-loop.log (crontab -l; crontab -l | grep -q "killall -g --older-than 5m oref0" || echo '* * * * * find /var/log/openaps/pump-loop.log -mmin +5 | grep pump && ( killall -g --older-than 5m openaps; killall -g --older-than 5m oref0-pump-loop; killall -g --older-than 5m openaps-report )') | crontab - - # remove pump_loop_completed on reboot so mmtune runs immediately on reboot - (crontab -l; crontab -l | grep -q "rm $directory/monitor/pump_loop_completed" || echo "@reboot rm $directory/monitor/pump_loop_completed") | crontab - if [[ ${CGM,,} =~ "shareble" || ${CGM,,} =~ "g4-upload" ]]; then (crontab -l; crontab -l | grep -q "cd $directory-cgm-loop && ps aux | grep -v grep | grep -q 'openaps monitor-cgm'" || echo "* * * * * cd $directory-cgm-loop && ps aux | grep -v grep | grep -q 'openaps monitor-cgm' || ( date; openaps monitor-cgm) | tee -a /var/log/openaps/cgm-loop.log; cp -up monitor/glucose-raw-merge.json $directory/cgm/glucose.json ; cp -up $directory/cgm/glucose.json $directory/monitor/glucose.json") | crontab - elif [[ ${CGM,,} =~ "xdrip" ]]; then From 014426a3bdc8b94b280a71f8cf0516373fe70d02 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 24 Sep 2017 15:44:53 -0700 Subject: [PATCH 107/215] revert incorrect /tmp/pump_loop_completed change --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 216429e56..e55c0e2bc 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -526,7 +526,7 @@ function wait_for_bg { touch -d "$(date -R -d @$(jq .[0].date/1000 monitor/glucose.json))" monitor/glucose.json if (! ls /tmp/pump_loop_completed >/dev/null ); then break - elif (find /tmp/ -newer /tmp/pump_loop_completed | grep -q glucose.json); then + elif (find monitor/ -newer /tmp/pump_loop_completed | grep -q glucose.json); then echo glucose.json newer than pump_loop_completed break else From e915dac7b804456cc6c0e36374d8af9812e79dda Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 24 Sep 2017 19:06:41 -0700 Subject: [PATCH 108/215] print hour numbers in autosens output (#671) * print hour numbers in autosens output * better differentiate hours from grams --- lib/determine-basal/autosens.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/determine-basal/autosens.js b/lib/determine-basal/autosens.js index 30d5a8c99..5adb6be6f 100644 --- a/lib/determine-basal/autosens.js +++ b/lib/determine-basal/autosens.js @@ -176,7 +176,7 @@ function detectSensitivity(inputs) { mealCOB += parseFloat(treatment.carbs); mealCarbs += parseFloat(treatment.carbs); displayCOB = Math.round(mealCOB); - process.stderr.write(displayCOB.toString()); + process.stderr.write(displayCOB.toString()+"g"); } meals.pop(); } @@ -204,7 +204,7 @@ function detectSensitivity(inputs) { // check previous "type" value, and if it wasn't csf, set a mealAbsorption start flag //console.error(type); if ( type != "csf" ) { - process.stderr.write("g("); + process.stderr.write("("); mealStartCounter = 0; //glucoseDatum.mealAbsorption = "start"; //console.error(glucoseDatum.mealAbsorption,"carb absorption"); @@ -265,7 +265,12 @@ function detectSensitivity(inputs) { deviationSum += parseFloat(deviation); } else { process.stderr.write("x"); + } + var minutes = bgTime.getMinutes(); + var hours = bgTime.getHours(); + if ( minutes >= 0 && minutes < 5 ) { //console.error(bgTime); + process.stderr.write(hours.toString()+"h"); } var lookback = inputs.deviations; if (!lookback) { lookback = 96; } From 597412d87b84b7df5b4f0c6ec74f52ce2372cd73 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 24 Sep 2017 19:07:32 -0700 Subject: [PATCH 109/215] properly calculate minguardBG if COB==0 and UAM is disabled (#673) * properly calculate minguardBG if COB==0 and UAM is off * properly calculate minguardBG if COB==0 and UAM is off * typo --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index c579b1c6f..9e08ac40e 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -424,7 +424,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } else if ( enableUAM ) { if ( UAMpredBG < minGuardBG ) { minGuardBG = round(UAMpredBG); } } else { - if ( IOBpredBG < minIOBPredBG ) { minIOBPredBG = round(IOBpredBG); } + if ( IOBpredBG < minGuardBG ) { minGuardBG = round(IOBpredBG); } } // wait 90m before setting minIOBPredBG if ( IOBpredBGs.length > 18 && (IOBpredBG < minIOBPredBG) ) { minIOBPredBG = round(IOBpredBG); } From 361c2ff5724351cb7a2a56c60a408bd2d54a7c32 Mon Sep 17 00:00:00 2001 From: Scott Date: Sun, 24 Sep 2017 20:04:37 -0700 Subject: [PATCH 110/215] fix test --- tests/determine-basal.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js index d8f833a19..af28827db 100644 --- a/tests/determine-basal.test.js +++ b/tests/determine-basal.test.js @@ -242,7 +242,7 @@ describe('determine-basal', function ( ) { var output = determine_basal(glucose_status, currenttemp, iob_data, profile, undefined, meal_data, tempBasalFunctions); output.rate.should.equal(0.9); output.duration.should.equal(30); - output.reason.should.match(/basaliob .* > max_iob .*/); + output.reason.should.match(/IOB .* > max_iob .*/); }); it('should temp to 0 when LOW w/ positive IOB', function () { From d192e52cb5de27f76859f2574f30b81f0a854a3b Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 25 Sep 2017 15:58:13 -0700 Subject: [PATCH 111/215] recalculate IOB and predBGs after each loop (#674) * recalculate IOB and predBGs after refreshing everything * don't print determine-basal output * no need to refresh temp again or display suggested.json output * print new IOB from refreshed smb-suggested.json * no newline after Settings line --- bin/oref0-pump-loop.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index e55c0e2bc..80fa4ff5c 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -228,6 +228,9 @@ function refresh_after_bolus_or_enact { # refresh profile if >5m old to give SMB a chance to deliver refresh_profile 3 gather || ( wait_for_silence 10 && gather ) || ( wait_for_silence 20 && gather ) + openaps report invoke enact/smb-suggested.json 2>/dev/null >/dev/null \ + && cp -up enact/smb-suggested.json enact/suggested.json \ + && echo -n "IOB: " && cat enact/smb-suggested.json | jq .IOB true fi @@ -512,8 +515,8 @@ function refresh_profile { else profileage=$1 fi - find settings/ -mmin -$profileage -size +5c | grep -q settings.json && echo Settings less than $profileage minutes old \ - || (echo -n Settings refresh && openaps get-settings 2>/dev/null >/dev/null && echo ed) + find settings/ -mmin -$profileage -size +5c | grep -q settings.json && echo -n "Settings less than $profileage minutes old. " \ + || (echo -n Settings refresh && openaps get-settings 2>/dev/null >/dev/null && echo -n "ed. ") } function wait_for_bg { From 02aca0365408fa5927a0efdbf0f45b2c57e854cc Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 25 Sep 2017 21:24:09 -0700 Subject: [PATCH 112/215] add allDeviations to meal.json output for UAM monitoring (#675) --- lib/determine-basal/cob.js | 7 ++++++- lib/meal/total.js | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/determine-basal/cob.js b/lib/determine-basal/cob.js index 06f5073cc..258bee902 100644 --- a/lib/determine-basal/cob.js +++ b/lib/determine-basal/cob.js @@ -102,6 +102,7 @@ function detectCarbAbsorption(inputs) { var slopeFromMinDeviation = 999; var maxDeviation = 0; var minDeviation = 999; + var allDeviations = []; //console.error(bucketed_data); for (var i=0; i < bucketed_data.length-3; ++i) { var bgTime = new Date(bucketed_data[i].date); @@ -142,6 +143,7 @@ function detectCarbAbsorption(inputs) { currentDeviation = Math.round((avgDelta-bgi)*1000)/1000; if (ciTime > bgTime) { //console.error("currentDeviation:",currentDeviation,avgDelta,bgi); + allDeviations.push(currentDeviation); } if (currentDeviation/2 > profile.min_5m_carbimpact) { //console.error("currentDeviation",currentDeviation,"/2 > min_5m_carbimpact",profile.min_5m_carbimpact); @@ -159,7 +161,9 @@ function detectCarbAbsorption(inputs) { minDeviation = avgDeviation; } - //console.error("Deviations:",bgTime, avgDeviation, deviationSlope, slopeFromMaxDeviation, slopeFromMinDeviation, avgDelta,bgi); + //console.error("Deviations:",avgDeviation, avgDelta,bgi,bgTime); + allDeviations.push(avgDeviation); + //console.error(allDeviations); } // if bgTime is more recent than mealTime @@ -184,6 +188,7 @@ function detectCarbAbsorption(inputs) { , "minDeviation": minDeviation , "slopeFromMaxDeviation": slopeFromMaxDeviation , "slopeFromMinDeviation": slopeFromMinDeviation + , "allDeviations": allDeviations } return output; } diff --git a/lib/meal/total.js b/lib/meal/total.js index c4fca109d..6908fc85f 100644 --- a/lib/meal/total.js +++ b/lib/meal/total.js @@ -83,7 +83,6 @@ function recentCarbs(opts, time) { mealCOB = 0; } - return { carbs: Math.round( carbs * 1000 ) / 1000 , mealCOB: Math.round( mealCOB ) @@ -92,6 +91,7 @@ function recentCarbs(opts, time) { , minDeviation: Math.round( c.minDeviation * 100 ) / 100 , slopeFromMaxDeviation: Math.round( c.slopeFromMaxDeviation * 1000 ) / 1000 , slopeFromMinDeviation: Math.round( c.slopeFromMinDeviation * 1000 ) / 1000 + , allDeviations: c.allDeviations }; } From bc8d4decbbf86d9d53981415249b834ef056fe1f Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 25 Sep 2017 21:26:23 -0700 Subject: [PATCH 113/215] remove extra minPredBG in rT object (#676) * remove extra minPredBG in rT object * remove extra minPredBG in rT object --- lib/determine-basal/determine-basal.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 481b1516a..80eb211e0 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -242,7 +242,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ , 'insulinReq': 0 , 'reservoir' : reservoir_data // The expected reservoir volume at which to deliver the microbolus (the reservoir volume from right before the last pumphistory run) , 'deliverAt' : deliverAt // The time at which the microbolus should be delivered - , 'minPredBG' : 999 }; var basaliob = iob_data.basaliob; @@ -837,7 +836,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ rate = round_basal(rate, profile); insulinReq = round(insulinReq,3); rT.insulinReq = insulinReq; - rT.minPredBG = minPredBG; //console.error(iob_data.lastBolusTime); // minutes since last bolus var lastBolusAge = round(( new Date().getTime() - iob_data.lastBolusTime ) / 60000,1); From fc938f54ac1fe1506808d7347f60163dec91b24b Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 25 Sep 2017 21:30:11 -0700 Subject: [PATCH 114/215] autotune de-biasing (#668) * ignore last CR period if COB > 0 at midnight * allow slightly positive avgDeltas to contribute to ISF to remove upward bias * capture 12h more for UTC-dated treatments * downgrade API_SECRET check to a warning, as readable sites work w/o it * cap ISF and CR before adjusting, not just after * debugging * don't recategorize ISF as basal if BGI > 0 and ISF < 0 * use avgDeltas up to -2*BGI for ISF * allow full autotune ISF adjustment now that safety caps fully apply * apply 20% of ISF adjustment now * remove CSF now that it's not used for anything * comment out unused code * only use CSF data if UAM data is insufficient * ignore negative ISFs * only use CSF data for ISF if ISFLength < 10 --- bin/oref0-autotune-recommends-report.sh | 10 ++--- bin/oref0-autotune.sh | 8 ++-- lib/autotune-prep/categorize.js | 27 +++++++------- lib/autotune/index.js | 49 +++++++++++++++---------- lib/profile/index.js | 2 +- 5 files changed, 55 insertions(+), 41 deletions(-) diff --git a/bin/oref0-autotune-recommends-report.sh b/bin/oref0-autotune-recommends-report.sh index 2c0fb89c2..fffc2e094 100755 --- a/bin/oref0-autotune-recommends-report.sh +++ b/bin/oref0-autotune-recommends-report.sh @@ -69,11 +69,11 @@ printf "%s\n" "-------------------------------------" >> $report_file # Print ISF, CSF and Carb Ratio Recommendations printf "%-${parameter_width}s| %-${data_width}.3f| %-${data_width}.3f\n" "ISF [mg/dL/U]" $isf_current $isf_new >> $report_file -if [ $csf_current != null ]; then - printf "%-${parameter_width}s| %-${data_width}.3f| %-${data_width}.3f\n" "CSF [mg/dL/g]" $csf_current $csf_new >> $report_file -else - printf "%-${parameter_width}s| %-${data_width}s| %-${data_width}.3f\n" "CSF [mg/dL/g]" "n/a" $csf_new >> $report_file -fi +# if [ $csf_current != null ]; then + # printf "%-${parameter_width}s| %-${data_width}.3f| %-${data_width}.3f\n" "CSF [mg/dL/g]" $csf_current $csf_new >> $report_file +# else + # printf "%-${parameter_width}s| %-${data_width}s| %-${data_width}.3f\n" "CSF [mg/dL/g]" "n/a" $csf_new >> $report_file +# fi printf "%-${parameter_width}s| %-${data_width}.3f| %-${data_width}.3f\n" "Carb Ratio[g/U]" $carb_ratio_current $carb_ratio_new >> $report_file # Print Basal Profile Recommendations diff --git a/bin/oref0-autotune.sh b/bin/oref0-autotune.sh index 1b1ecac32..7bdb6f9a2 100755 --- a/bin/oref0-autotune.sh +++ b/bin/oref0-autotune.sh @@ -49,8 +49,8 @@ if [ -n "${API_SECRET_READ}" ]; then fi if [[ -z "$API_SECRET" ]]; then - echo "ERROR: API_SECRET is not set when calling oref0-autotune.sh" - exit 1 + echo "Warning: API_SECRET is not set when calling oref0-autotune.sh" + # exit 1 fi # If we are running OS X, we need to use a different version @@ -189,7 +189,9 @@ do # Get Nightscout carb and insulin Treatments # echo $i $START_DATE; #query="find%5Bdate%5D%5B%24gte%5D=`(date -d $i +%s | tr -d'\n'; echo 000)`&find%5Bdate%5D%5B%24lte%5D=`(date --date="$i +1 days" +%s | tr -d '\n'; echo 000)`&count=1000" - query="find%5Bcreated_at%5D%5B%24gte%5D=`date --date="$i -5 hours" -Iminutes`&find%5Bcreated_at%5D%5B%24lte%5D=`date --date="$i +1 days" -Iminutes`" + # to capture UTC-dated treatments, we need to capture an extra 12h on either side, plus the DIA lookback + # 18h = 12h for timezones + 6h for DIA; 36h = 24h for end-of-day + 12h for timezones + query="find%5Bcreated_at%5D%5B%24gte%5D=`date --date="$i -18 hours" -Iminutes`&find%5Bcreated_at%5D%5B%24lte%5D=`date --date="$i +36 hours" -Iminutes`" echo Query: $NIGHTSCOUT_HOST/$query ns-get host $NIGHTSCOUT_HOST treatments.json $query > ns-treatments.$i.json || die "Couldn't download ns-treatments.$i.json" ls -la ns-treatments.$i.json || die "No ns-treatments.$i.json downloaded" diff --git a/lib/autotune-prep/categorize.js b/lib/autotune-prep/categorize.js index 378301f9a..c3e2d5615 100644 --- a/lib/autotune-prep/categorize.js +++ b/lib/autotune-prep/categorize.js @@ -233,7 +233,7 @@ function categorizeBGDatums(opts) { var CRElapsedMinutes = Math.round((CREndTime - CRInitialCarbTime) / 1000 / 60); //console.error(CREndTime - CRInitialCarbTime, CRElapsedMinutes); - if ( CRElapsedMinutes < 60 ) { + if ( CRElapsedMinutes < 60 || ( i==1 && mealCOB > 0 ) ) { console.error("Ignoring",CRElapsedMinutes,"m CR period."); } else { CRData.push(CRDatum); @@ -277,7 +277,6 @@ function categorizeBGDatums(opts) { console.error(CSFGlucoseData[CSFGlucoseData.length-1].mealAbsorption,"carb absorption"); } - // check that we have a decent amount of basal tuning data before excluding data as UAM if ((iob.iob > currentBasal || uam) ) { if (deviation > 0) { uam = 1; @@ -303,7 +302,7 @@ function categorizeBGDatums(opts) { // unless avgDelta is positive: then that's some sort of unexplained rise we don't want to use for ISF, so that means basals if (basalBGI > -4 * BGI) { // attempting to prevent basal from being calculated as negative; should help prevent basals from going below 0 - var minPossibleDeviation = -( basalBGI + Math.max(0,BGI) ); + //var minPossibleDeviation = -( basalBGI + Math.max(0,BGI) ); //var minPossibleDeviation = -basalBGI; //if ( deviation < minPossibleDeviation ) { //console.error("Adjusting deviation",deviation,"to",minPossibleDeviation.toFixed(2)); @@ -314,7 +313,7 @@ function categorizeBGDatums(opts) { type="basal"; basalGlucoseData.push(glucoseDatum); } else { - if (avgDelta > 0 ) { + if ( avgDelta > 0 && avgDelta > -2*BGI ) { //type="unknown" type="basal" basalGlucoseData.push(glucoseDatum); @@ -353,15 +352,6 @@ function categorizeBGDatums(opts) { var UAMLength = UAMGlucoseData.length; var basalLength = basalGlucoseData.length; - if (4*basalLength < CSFLength) { - console.error("Warning: too many deviations categorized as meals"); - //console.error("Adding",CSFLength,"CSF deviations to",basalLength,"basal ones"); - //var basalGlucoseData = basalGlucoseData.concat(CSFGlucoseData); - console.error("Adding",CSFLength,"CSF deviations to",ISFLength,"ISF ones"); - var ISFGlucoseData = ISFGlucoseData.concat(CSFGlucoseData); - CSFGlucoseData = []; - } - if (2*basalLength < UAMLength) { //console.error(basalGlucoseData, UAMGlucoseData); console.error("Warning: too many deviations categorized as UnAnnounced Meals"); @@ -371,6 +361,17 @@ function categorizeBGDatums(opts) { var ISFGlucoseData = ISFGlucoseData.concat(UAMGlucoseData); //console.error(ISFGlucoseData.length, UAMLength); } + var basalLength = basalGlucoseData.length; + var ISFLength = ISFGlucoseData.length; + if ( 4*basalLength + ISFLength < CSFLength && ISFLength < 10 ) { + console.error("Warning: too many deviations categorized as meals"); + //console.error("Adding",CSFLength,"CSF deviations to",basalLength,"basal ones"); + //var basalGlucoseData = basalGlucoseData.concat(CSFGlucoseData); + console.error("Adding",CSFLength,"CSF deviations to",ISFLength,"ISF ones"); + var ISFGlucoseData = ISFGlucoseData.concat(CSFGlucoseData); + CSFGlucoseData = []; + } + return { CRData: CRData, diff --git a/lib/autotune/index.js b/lib/autotune/index.js index b29f2e588..022974407 100644 --- a/lib/autotune/index.js +++ b/lib/autotune/index.js @@ -281,9 +281,21 @@ function tuneAllTheThings (inputs) { // how much change would be required to account for all of the deviations fullNewCR = totalCR; } - // only adjust by 10% + // safety cap fullNewCR + if (typeof(pumpCarbRatio) !== 'undefined') { + var maxCR = pumpCarbRatio * autotuneMax; + var minCR = pumpCarbRatio * autotuneMin; + if (fullNewCR > maxCR) { + console.error("Limiting fullNewCR from",fullNewCR,"to",maxCR.toFixed(2),"(which is",autotuneMax,"* pump CR of",pumpCarbRatio,")"); + fullNewCR = maxCR; + } else if (fullNewCR < minCR) { + console.error("Limiting fullNewCR from",fullNewCR,"to",minCR.toFixed(2),"(which is",autotuneMin,"* pump CR of",pumpCarbRatio,")"); + fullNewCR = minCR; + } //else { console.error("newCR",newCR,"is close enough to",pumpCarbRatio); } + } + // only adjust by 20% newCR = ( 0.8 * carbRatio ) + ( 0.2 * fullNewCR ); - // safety cap CR + // safety cap newCR if (typeof(pumpCarbRatio) !== 'undefined') { var maxCR = pumpCarbRatio * autotuneMax; var minCR = pumpCarbRatio * autotuneMin; @@ -298,10 +310,10 @@ function tuneAllTheThings (inputs) { newCR = Math.round( newCR * 1000 ) / 1000; console.error("oldCR:",carbRatio,"fullNewCR:",fullNewCR,"newCR:",newCR); // this is where CR is set based on the outputs - var ISFFromCRAndCSF = ISF; + //var ISFFromCRAndCSF = ISF; if (newCR) { carbRatio = newCR; - ISFFromCRAndCSF = Math.round( carbRatio * CSF * 1000)/1000; + //ISFFromCRAndCSF = Math.round( carbRatio * CSF * 1000)/1000; } @@ -331,7 +343,7 @@ function tuneAllTheThings (inputs) { p50deviation = percentile(deviations, 0.50); p50BGI = percentile(BGIs, 0.50); p50ratios = Math.round( percentile(ratios, 0.50) * 1000)/1000; - if (count < 5) { + if (count < 10) { // leave ISF unchanged if fewer than 5 ISF data points fullNewISF = ISF; } else { @@ -344,11 +356,20 @@ function tuneAllTheThings (inputs) { if (pumpProfile.autotune_isf_adjustmentFraction) { adjustmentFraction = pumpProfile.autotune_isf_adjustmentFraction; } else { - adjustmentFraction = 0.5; + adjustmentFraction = 1.0; } + // low autosens ratio = high ISF + var maxISF = pumpISF / autotuneMin; + // high autosens ratio = low ISF + var minISF = pumpISF / autotuneMax; if (typeof(pumpISF) !== 'undefined') { - var adjustedISF = adjustmentFraction*fullNewISF + (1-adjustmentFraction)*pumpISF; + if ( fullNewISF < 0 ) { + var adjustedISF = ISF; + } else { + var adjustedISF = adjustmentFraction*fullNewISF + (1-adjustmentFraction)*pumpISF; + } // cap adjustedISF before applying 10% + //console.error(adjustedISF, maxISF, minISF); if (adjustedISF > maxISF) { console.error("Limiting adjusted ISF of",adjustedISF.toFixed(2),"to",maxISF.toFixed(2),"(which is pump ISF of",pumpISF,"/",autotuneMin,")"); adjustedISF = maxISF; @@ -357,19 +378,9 @@ function tuneAllTheThings (inputs) { adjustedISF = minISF; } - // average both the directly-calculated ISF and the ISFFromCRAndCSF if we're reasonably well tuned - if (p50ratios > 0.4 && p50ratios < 0.6) { - // TODO: figure out if there's a way to do this without messing up CSF tuning - // adjustedISF = (adjustedISF + ISFFromCRAndCSF) / 2; - } - - // and apply 10% of that adjustment - var newISF = ( 0.9 * ISF ) + ( 0.1 * adjustedISF ); + // and apply 20% of that adjustment + var newISF = ( 0.8 * ISF ) + ( 0.2 * adjustedISF ); - // low autosens ratio = high ISF - var maxISF = pumpISF / autotuneMin; - // high autosens ratio = low ISF - var minISF = pumpISF / autotuneMax; if (newISF > maxISF) { console.error("Limiting ISF of",newISF.toFixed(2),"to",maxISF.toFixed(2),"(which is pump ISF of",pumpISF,"/",autotuneMin,")"); newISF = maxISF; diff --git a/lib/profile/index.js b/lib/profile/index.js index 1c2b06356..c8757a634 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -25,7 +25,7 @@ function defaults ( ) { , bolussnooze_dia_divisor: 2 // bolus snooze decays after 1/2 of DIA , min_5m_carbimpact: 8 // mg/dL per 5m (8 mg/dL/5m corresponds to 24g/hr at a CSF of 4 mg/dL/g (x/5*60/4)) , carbratio_adjustmentratio: 1 // if carb ratios on pump are set higher to lower initial bolus using wizard, .8 = assume only 80 percent of carbs covered with full bolus - , autotune_isf_adjustmentFraction: 0.5 // keep autotune ISF closer to pump ISF via a weighted average of fullNewISF and pumpISF. 1.0 allows full adjustment, 0 is no adjustment from pump ISF. + , autotune_isf_adjustmentFraction: 1.0 // keep autotune ISF closer to pump ISF via a weighted average of fullNewISF and pumpISF. 1.0 allows full adjustment, 0 is no adjustment from pump ISF. , remainingCarbsFraction: 1.0 // fraction of carbs we'll assume will absorb over 4h if we don't yet see carb absorption , remainingCarbsCap: 90 // max carbs we'll assume will absorb over 4h if we don't yet see carb absorption // WARNING: the following are advanced oref1 features, and are not yet tested for general use From a3834b46691af11b092a1465fbf6305a097b086d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 28 Sep 2017 07:09:22 -0700 Subject: [PATCH 115/215] randomize wait_for_silence before smb_verify_reservoir (#679) * randomize wait_for_silence before smb_verify_reservoir * typo --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 80fa4ff5c..ebe0a2bcf 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -110,7 +110,7 @@ function smb_check_everything { && smb_enact_temp \ && if (grep -q '"units":' enact/smb-suggested.json); then ( smb_verify_suggested || smb_suggest ) \ - && wait_for_silence 1 \ + && echo -n "Listening for $upto10s s silence: " && wait_for_silence $upto10s \ && smb_verify_reservoir \ && smb_verify_status \ || ( echo Retrying SMB checks From 7d1e8054c33d862cdf093f4d2018fe381d1240f9 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 28 Sep 2017 20:48:19 -0700 Subject: [PATCH 116/215] use lastCarbAge to calculate remainingCATime (#678) * use lastCarbAge instead of fractionCOBAbsorbed to calculate remainingCATime * set lastCarbTime based on the max treatmentTime * remainingCATimeMax is now unused --- lib/determine-basal/determine-basal.js | 8 +++++--- lib/meal/total.js | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 80eb211e0..ecb1ded8a 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -302,18 +302,20 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // meal_carbimpact (mg/dL/5m) = CSF (mg/dL/g) * carbs (g) / 6 (h) * (1h/60m) * 5 (m/5m) * 2 (for linear decay) //var meal_carbimpact = round((csf * meal_data.carbs / 6 / 60 * 5 * 2),1) var remainingCATimeMin = 3; // h; before carb absorption starts - var remainingCATimeMax = 6; // h; just before carb absorption ends var carbAbsorptionRate = 30; // g/h; maximum rate to assume carbs will absorb if no CI observed var remainingCATime; if (meal_data.carbs) { // if carbs * carbAbsorptionRate > remainingCATimeMin, raise it // so <= 90g is assumed to take 3h, and 120g=4h remainingCATimeMin = Math.max(remainingCATimeMin, meal_data.carbs/carbAbsorptionRate); + var lastCarbAge = round(( new Date().getTime() - meal_data.lastCarbTime ) / 60000); + //console.error(meal_data.lastCarbTime, lastCarbAge); + fractionCOBAbsorbed = ( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs; - remainingCATime = remainingCATimeMin*(1-fractionCOBAbsorbed) + remainingCATimeMax*fractionCOBAbsorbed; + remainingCATime = remainingCATimeMin + lastCarbAge/60; remainingCATime = round(remainingCATime,1); //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) - console.error("Adjusting remainingCATime to",remainingCATime,"h based on",round(fractionCOBAbsorbed*100)+"% carb absorption"); + console.error("Last carbs",lastCarbAge,"minutes ago; remainingCATime:",remainingCATime,"hours;",round(fractionCOBAbsorbed*100)+"% carbs absorbed"); } // calculate the number of carbs absorbed over remainingCATime hours at current CI diff --git a/lib/meal/total.js b/lib/meal/total.js index 6908fc85f..266185343 100644 --- a/lib/meal/total.js +++ b/lib/meal/total.js @@ -11,6 +11,7 @@ function recentCarbs(opts, time) { var carbDelay = 20 * 60 * 1000; var maxCarbs = 0; var mealCarbTime = time.getTime(); + var lastCarbTime = 0; if (!treatments) return {}; //console.error(glucose_data); @@ -46,6 +47,7 @@ function recentCarbs(opts, time) { //console.error(treatment.carbs, maxCarbs, treatmentDate); carbs += parseFloat(treatment.carbs); COB_inputs.mealTime = treatmentTime; + lastCarbTime = Math.max(lastCarbTime,treatmentTime); var myCarbsAbsorbed = calcMealCOB(COB_inputs).carbsAbsorbed; var myMealCOB = Math.max(0, carbs - myCarbsAbsorbed); mealCOB = Math.max(mealCOB, myMealCOB); @@ -92,6 +94,7 @@ function recentCarbs(opts, time) { , slopeFromMaxDeviation: Math.round( c.slopeFromMaxDeviation * 1000 ) / 1000 , slopeFromMinDeviation: Math.round( c.slopeFromMinDeviation * 1000 ) / 1000 , allDeviations: c.allDeviations + , lastCarbTime: lastCarbTime }; } From 3bd4605b6a31f76b2bfea95b768cdb1b809af2e9 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 28 Sep 2017 20:49:04 -0700 Subject: [PATCH 117/215] add an enableSMB_always option (#677) * add an enableSMB_always option * disable SMB on really big jumps for safety * add SMB disabled to reason field if delta > 10% of bg --- lib/determine-basal/determine-basal.js | 9 +++++++++ lib/profile/index.js | 1 + 2 files changed, 10 insertions(+) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index ecb1ded8a..d072f9e70 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -266,6 +266,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // disable SMB when a high temptarget is set if (profile.temptargetSet && target_bg > 100) { enableSMB=false; + // enable SMB/UAM if always-on (unless previously disabled for high temptarget) + } else if (profile.enableSMB_always) { + enableSMB=true; // enable SMB/UAM (if enabled in preferences) for DIA hours after bolus } else if (profile.enableSMB_with_bolus && bolusiob > 0.1) { enableSMB=true; @@ -620,6 +623,12 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if (enableSMB && minGuardBG < threshold) { console.error("minGuardBG",minGuardBG,"projected below",threshold,"- disabling SMB"); + //rT.reason += "minGuardBG "+minGuardBG+"<"+threshold+": SMB disabled; "; + enableSMB = false; + } + if ( glucose_status.delta > 0.1 * bg ) { + console.error("Delta",glucose_status.delta,"> 10% of BG",bg,"- disabling SMB"); + rT.reason += "Delta "+glucose_status.delta+" > 10% of BG "+bg+": SMB disabled; "; enableSMB = false; } diff --git a/lib/profile/index.js b/lib/profile/index.js index c8757a634..5b6d41120 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -30,6 +30,7 @@ function defaults ( ) { , remainingCarbsCap: 90 // max carbs we'll assume will absorb over 4h if we don't yet see carb absorption // WARNING: the following are advanced oref1 features, and are not yet tested for general use , enableUAM: false // enable detection of unannounced meal carb absorption + , enableSMB_always: false // always enable supermicrobolus (unless disabled by high temptarget) , enableSMB_with_bolus: false // enable supermicrobolus for DIA hours after a manual bolus , enableSMB_with_COB: false // enable supermicrobolus while COB is positive , enableSMB_with_temptarget: false // enable supermicrobolus for eating soon temp targets From a81f007b691939a4179be87a56e81bd80b1eef3d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 28 Sep 2017 20:51:02 -0700 Subject: [PATCH 118/215] recalculate IOB before re-doing smb-suggested.json (#680) --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index ebe0a2bcf..018c72c3c 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -228,7 +228,7 @@ function refresh_after_bolus_or_enact { # refresh profile if >5m old to give SMB a chance to deliver refresh_profile 3 gather || ( wait_for_silence 10 && gather ) || ( wait_for_silence 20 && gather ) - openaps report invoke enact/smb-suggested.json 2>/dev/null >/dev/null \ + openaps report invoke monitor/iob.json enact/smb-suggested.json 2>/dev/null >/dev/null \ && cp -up enact/smb-suggested.json enact/suggested.json \ && echo -n "IOB: " && cat enact/smb-suggested.json | jq .IOB true From c65ee94b95bdfecec520b52a9c79a11d274287c3 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 28 Sep 2017 20:51:49 -0700 Subject: [PATCH 119/215] round basalNeeded to .01 to make it easier to read (#681) --- lib/autotune/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/autotune/index.js b/lib/autotune/index.js index 022974407..2c622f88e 100644 --- a/lib/autotune/index.js +++ b/lib/autotune/index.js @@ -122,7 +122,7 @@ function tuneAllTheThings (inputs) { // calculate how much less or additional basal insulin would have been required to eliminate the deviations // only apply 20% of the needed adjustment to keep things relatively stable basalNeeded = 0.2 * deviations / ISF; - basalNeeded = Math.round( basalNeeded * 1000 ) / 1000 + basalNeeded = Math.round( basalNeeded * 100 ) / 100 // if basalNeeded is positive, adjust each of the 1-3 hour prior basals by 10% of the needed adjustment console.error("Hour",hour,"basal adjustment needed:",basalNeeded,"U/hr"); if (basalNeeded > 0 ) { From 13cd96f6561399cf9db894d32970aa063b0890e2 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 2 Oct 2017 12:03:40 -0700 Subject: [PATCH 120/215] look ahead an additional 15m to get insulin started faster (#683) * look ahead an additional 15m to get insulin started faster * ramp up remainingCATime 1.5x as fast as lastCarbAge --- lib/determine-basal/determine-basal.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index d072f9e70..1ef227832 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -315,7 +315,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //console.error(meal_data.lastCarbTime, lastCarbAge); fractionCOBAbsorbed = ( meal_data.carbs - meal_data.mealCOB ) / meal_data.carbs; - remainingCATime = remainingCATimeMin + lastCarbAge/60; + remainingCATime = remainingCATimeMin + 1.5 * lastCarbAge/60; remainingCATime = round(remainingCATime,1); //console.error(fractionCOBAbsorbed, remainingCATimeAdjustment, remainingCATime) console.error("Last carbs",lastCarbAge,"minutes ago; remainingCATime:",remainingCATime,"hours;",round(fractionCOBAbsorbed*100)+"% carbs absorbed"); @@ -443,15 +443,15 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if ( profile.curve == "ultra-rapid" && !profile.useCustomPeakTime ) { insulinPeakTime = 55; } - // add 15m to allow for insluin delivery (SMBs or temps) - insulinPeakTime += 15; + // add 30m to allow for insluin delivery (SMBs or temps) + insulinPeakTime += 30; var insulinPeak5m = (insulinPeakTime/60)*12; //console.error(insulinPeakTime, insulinPeak5m, profile.insulinPeakTime, profile.curve); - // wait 70-90m before setting minIOBPredBG + // wait 80-100 before setting minIOBPredBG if ( IOBpredBGs.length > insulinPeak5m && (IOBpredBG < minIOBPredBG) ) { minIOBPredBG = round(IOBpredBG); } if ( IOBpredBG > maxIOBPredBG ) { maxIOBPredBG = IOBpredBG; } - // wait 70-90m before setting COB and 60m for UAM minPredBGs + // wait 85-105m before setting COB and 60m for UAM minPredBGs if ( (cid || remainingCIpeak > 0) && COBpredBGs.length > insulinPeak5m && (COBpredBG < minCOBPredBG) ) { minCOBPredBG = round(COBpredBG); } if ( (cid || remainingCIpeak > 0) && COBpredBG > maxIOBPredBG ) { maxCOBPredBG = COBpredBG; } if ( enableUAM && UAMpredBGs.length > 12 && (UAMpredBG < minUAMPredBG) ) { minUAMPredBG = round(UAMpredBG); } From 0d80ef046ca065607879c92196eaa38a83af75c0 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 5 Oct 2017 20:14:23 -0700 Subject: [PATCH 121/215] curl openaps-install.sh (#697) * use curl instead of wget --no-check-certificate * use the version of openaps-install.sh in oref0 master --- bin/openaps-bootstrap.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/openaps-bootstrap.sh b/bin/openaps-bootstrap.sh index d74b513d2..0f4065091 100644 --- a/bin/openaps-bootstrap.sh +++ b/bin/openaps-bootstrap.sh @@ -29,6 +29,6 @@ ifdown wlan0; ifup wlan0 sleep 10 echo -ne "\nWifi SSID: "; iwgetid -r sleep 5 -# TODO check for options to fix the certificate activation error message for https -cd /tmp/; wget --no-check-certificate https://raw.githubusercontent.com/openaps/docs/dev/scripts/openaps-install.sh; bash ./openaps-install.sh +curl https://raw.githubusercontent.com/openaps/oref0/master/bin/openaps-install.sh > /tmp/openaps-install.sh +bash /tmp/openaps-install.sh ) From 9b9a87c03624731835767591ba6e9dcfc120ca4a Mon Sep 17 00:00:00 2001 From: Scott Date: Thu, 5 Oct 2017 21:13:15 -0700 Subject: [PATCH 122/215] remove ,, for backwards compatibility with bash 3.x on Mac --- bin/ns-get.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/ns-get.sh b/bin/ns-get.sh index dc9b11efb..06b2a7b54 100755 --- a/bin/ns-get.sh +++ b/bin/ns-get.sh @@ -26,7 +26,7 @@ EOF CURL_AUTH="" # use token authentication if the user has a token set in their API_SECRET environment variable -if [[ "${API_SECRET,,}" =~ "token=" ]]; then +if [[ "${API_SECRET}" =~ "token=" ]]; then if [[ -z ${QUERY} ]]; then REPORT_ENDPOINT=$NIGHTSCOUT_HOST/api/v1/${REPORT}'?'${API_SECRET} else @@ -46,7 +46,7 @@ case $1 in OUTPUT=${5-/dev/fd/1} # use token authentication if the user has a token set in their API_SECRET environment variable - if [[ "${API_SECRET,,}" =~ "token=" ]]; then + if [[ "${API_SECRET}" =~ "token=" ]]; then if [[ -z ${QUERY} ]]; then REPORT_ENDPOINT=$NIGHTSCOUT_HOST/api/v1/${REPORT}'?'${API_SECRET} else From 8be8b333eac48c030efc141aa5433c5792658f46 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 5 Oct 2017 21:48:58 -0700 Subject: [PATCH 123/215] don't run loop if rig is too hot (#689) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * don't run pump-loop if rig is too hot * print error messages for overtemp * temp threshold 80C * fix comment * truncate ns-loop if rig is too hot * use 85°C --- bin/oref0-pump-loop.sh | 134 ++++++++++++++++++++----------------- lib/oref0-setup/alias.json | 2 +- 2 files changed, 73 insertions(+), 63 deletions(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 018c72c3c..5291d98a2 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -3,80 +3,90 @@ # main pump-loop main() { prep - until( \ - echo && echo Starting pump-loop at $(date): \ - && wait_for_bg \ - && wait_for_silence \ - && if_mdt_get_bg \ - && refresh_old_pumphistory_enact \ - && refresh_old_pumphistory_24h \ - && refresh_old_profile \ - && touch /tmp/pump_loop_enacted -r monitor/glucose.json \ - && ( refresh_temp_and_enact || ( smb_verify_status && refresh_temp_and_enact ) ) \ - && refresh_pumphistory_and_enact \ - && refresh_profile \ - && refresh_pumphistory_24h \ - && echo Completed pump-loop at $(date) \ - && touch /tmp/pump_loop_completed -r /tmp/pump_loop_enacted \ - && echo); do + if ! overtemp; then + until( \ + echo && echo Starting pump-loop at $(date): \ + && wait_for_bg \ + && wait_for_silence \ + && if_mdt_get_bg \ + && refresh_old_pumphistory_enact \ + && refresh_old_pumphistory_24h \ + && refresh_old_profile \ + && touch /tmp/pump_loop_enacted -r monitor/glucose.json \ + && ( refresh_temp_and_enact || ( smb_verify_status && refresh_temp_and_enact ) ) \ + && refresh_pumphistory_and_enact \ + && refresh_profile \ + && refresh_pumphistory_24h \ + && echo Completed pump-loop at $(date) \ + && touch /tmp/pump_loop_completed -r /tmp/pump_loop_enacted \ + && echo); do - if grep -q "percent" monitor/temp_basal.json; then - echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." - fi - # On a random subset of failures, mmtune - echo Error, retrying \ - && maybe_mmtune - sleep 5 - done + if grep -q "percent" monitor/temp_basal.json; then + echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." + fi + # On a random subset of failures, mmtune + echo Error, retrying \ + && maybe_mmtune + sleep 5 + done + fi } # main supermicrobolus loop smb_main() { prep - if ! ( \ - prep - # checking to see if the log reports out that it is on % basal type, which blocks remote temps being set - echo && echo Starting supermicrobolus pump-loop at $(date) with $upto30s second wait_for_silence: \ - && wait_for_bg \ - && wait_for_silence $upto30s \ - && ( preflight || preflight ) \ - && if_mdt_get_bg \ - && refresh_old_pumphistory_24h \ - && refresh_old_pumphistory \ - && refresh_old_profile \ - && touch /tmp/pump_loop_enacted -r monitor/glucose.json \ - && refresh_smb_temp_and_enact \ - && ( smb_check_everything \ - && if (grep -q '"units":' enact/smb-suggested.json); then - ( smb_bolus && \ - touch /tmp/pump_loop_completed -r /tmp/pump_loop_enacted \ + if ! overtemp; then + if ! ( \ + prep + # checking to see if the log reports out that it is on % basal type, which blocks remote temps being set + echo && echo Starting supermicrobolus pump-loop at $(date) with $upto30s second wait_for_silence: \ + && wait_for_bg \ + && wait_for_silence $upto30s \ + && ( preflight || preflight ) \ + && if_mdt_get_bg \ + && refresh_old_pumphistory_24h \ + && refresh_old_pumphistory \ + && refresh_old_profile \ + && touch /tmp/pump_loop_enacted -r monitor/glucose.json \ + && refresh_smb_temp_and_enact \ + && ( smb_check_everything \ + && if (grep -q '"units":' enact/smb-suggested.json); then + ( smb_bolus && \ + touch /tmp/pump_loop_completed -r /tmp/pump_loop_enacted \ + ) \ + || ( smb_old_temp && ( \ + echo "Falling back to normal pump-loop" \ + && refresh_temp_and_enact \ + && refresh_pumphistory_and_enact \ + && refresh_profile \ + && refresh_pumphistory_24h \ + && echo Completed pump-loop at $(date) \ + && echo \ + )) + fi ) \ - || ( smb_old_temp && ( \ - echo "Falling back to normal pump-loop" \ - && refresh_temp_and_enact \ - && refresh_pumphistory_and_enact \ - && refresh_profile \ - && refresh_pumphistory_24h \ - && echo Completed pump-loop at $(date) \ - && echo \ - )) + && ( refresh_profile 15; refresh_pumphistory_24h; true ) \ + && refresh_after_bolus_or_enact \ + && echo Completed supermicrobolus pump-loop at $(date): \ + && touch /tmp/pump_loop_completed -r /tmp/pump_loop_enacted \ + && echo \ + ); then + echo -n "SMB pump-loop failed. " + if grep -q "percent" monitor/temp_basal.json; then + echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." fi - ) \ - && ( refresh_profile 15; refresh_pumphistory_24h; true ) \ - && refresh_after_bolus_or_enact \ - && echo Completed supermicrobolus pump-loop at $(date): \ - && touch /tmp/pump_loop_completed -r /tmp/pump_loop_enacted \ - && echo \ - ); then - echo -n "SMB pump-loop failed. " - if grep -q "percent" monitor/temp_basal.json; then - echo "Pssst! Your pump is set to % basal type. The pump won’t accept temporary basal rates in this mode. Change it to absolute u/hr, and temporary basal rates will then be able to be set." + maybe_mmtune + echo Unsuccessful supermicrobolus pump-loop at $(date) fi - maybe_mmtune - echo Unsuccessful supermicrobolus pump-loop at $(date) fi } +function overtemp { + # check for CPU temperature above 85°C + sensors -u 2>/dev/null | awk '$NF > 85' | grep input \ + && echo Rig is too hot: not running pump-loop at $(date)\ + && echo Please ensure rig is properly ventilated +} function smb_reservoir_before { # Refresh reservoir.json and pumphistory.json gather \ diff --git a/lib/oref0-setup/alias.json b/lib/oref0-setup/alias.json index 7982cd9e3..a86fde1e4 100644 --- a/lib/oref0-setup/alias.json +++ b/lib/oref0-setup/alias.json @@ -171,7 +171,7 @@ "type": "alias", "name": "ns-loop", "ns-loop": { - "command": "! bash -c \"echo Starting ns-loop at $(date): && openaps get-ns-bg; openaps ns-temptargets && echo -n Refreshed temptargets && openaps ns-meal-carbs && echo \\\" and meal-carbs\\\" && openaps upload\"" + "command": "! bash -c \"echo Starting ns-loop at $(date): && openaps get-ns-bg; sensors -u 2>/dev/null | awk '$NF > 85' | grep input || ( openaps ns-temptargets && echo -n Refreshed temptargets && openaps ns-meal-carbs && echo \\\" and meal-carbs\\\" && openaps upload )\"" } }, { From 30c9b9fa752abd7437c9338db0a0d24c8d4bc423 Mon Sep 17 00:00:00 2001 From: Dana Lewis Date: Fri, 6 Oct 2017 13:22:27 -0700 Subject: [PATCH 124/215] Attempting to --nogit by default for existing user installs --- bin/oref0-setup.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index b6af15f74..b4ea5ae4b 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -499,6 +499,11 @@ echocolor-n "Continue? y/[N] " read -r if [[ $REPLY =~ ^[Yy]$ ]]; then + # Attempting to remove git to make install --nogit by default for existing users + echo Removing any existing git + rm -rf ~/myopenaps/.git + echo Removed any existing git + # TODO: delete this after openaps 0.2.1 release echo Checking openaps 0.2.1 installation with --nogit support if ! openaps --version 2>&1 | egrep "0.[2-9].[1-9]"; then @@ -507,9 +512,9 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then echo -n "Checking $directory: " mkdir -p $directory - if ( cd $directory && ls openaps.ini 2>/dev/null >/dev/null && openaps use -h >/dev/null ); then - echo $directory already exists - elif openaps init $directory --nogit; then + # if ( cd $directory && ls openaps.ini 2>/dev/null >/dev/null && openaps use -h >/dev/null ); then + # echo $directory already exists + if openaps init $directory --nogit; then echo $directory initialized else die "Can't init $directory" From fc990c2873765c3c0539a5049107832e119bbb5d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Fri, 6 Oct 2017 21:47:34 -0700 Subject: [PATCH 125/215] Blend minGuardBG (#698) * blend minCOBGuardBG and minUAMGuardBG according to fractionCarbsLeft * round(minGuardBG) * only use minUAMPredBG not avgMinPredBG * debugging output --- lib/determine-basal/determine-basal.js | 37 +++++++++++++++++++------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 1ef227832..5e76bbdc4 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -367,6 +367,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var minCOBPredBG = 999; var minUAMPredBG = 999; var minGuardBG = 999; + var minCOBGuardBG = 999; + var minUAMGuardBG = 999; + var minIOBGuardBG = 999; var minPredBG; var avgPredBG; var IOBpredBG = eventualBG; @@ -426,14 +429,10 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if ( COBpredBGs.length < 48) { COBpredBGs.push(COBpredBG); } if ( aCOBpredBGs.length < 48) { aCOBpredBGs.push(aCOBpredBG); } if ( UAMpredBGs.length < 48) { UAMpredBGs.push(UAMpredBG); } - // calculate minGuardBG without a wait from COB if available, or UAM, or IOB predBGs - if ( (cid || remainingCIpeak > 0) && fractionCOBAbsorbed < 0.75 ) { - if ( COBpredBG < minGuardBG ) { minGuardBG = round(COBpredBG); } - } else if ( enableUAM ) { - if ( UAMpredBG < minGuardBG ) { minGuardBG = round(UAMpredBG); } - } else { - if ( IOBpredBG < minGuardBG ) { minGuardBG = round(IOBpredBG); } - } + // calculate minGuardBGs without a wait from COB, UAM, IOB predBGs + if ( COBpredBG < minCOBGuardBG ) { minCOBGuardBG = round(COBpredBG); } + if ( UAMpredBG < minUAMGuardBG ) { minUAMGuardBG = round(UAMpredBG); } + if ( IOBpredBG < minIOBGuardBG ) { minIOBGuardBG = round(IOBpredBG); } // set minPredBGs starting when currently-dosed insulin activity will peak var insulinPeakTime = 75; @@ -520,6 +519,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ console.error("UAM Impact:",uci,"mg/dL per 5m; UAM Duration:",UAMduration,"hours"); + minIOBPredBG = Math.max(39,minIOBPredBG); minCOBPredBG = Math.max(39,minCOBPredBG); minUAMPredBG = Math.max(39,minUAMPredBG); @@ -540,14 +540,31 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ avgPredBG = round( IOBpredBG ); } + // if we have both minCOBGuardBG and minUAMGuardBG, blend according to fractionCarbsLeft + if ( (cid || remainingCIpeak > 0) && enableUAM ) { + if ( enableUAM ) { + minGuardBG = fractionCarbsLeft*minCOBGuardBG + (1-fractionCarbsLeft)*minUAMGuardBG; + } else { + minGuardBG = minCOBGuardBG; + } + } else if ( enableUAM ) { + minGuardBG = minUAMGuardBG; + } else { + minGuardBG = minIOBGuardBG; + } + minGuardBG = round(minGuardBG); + //console.error(minCOBGuardBG, minUAMGuardBG, minIOBGuardBG, minGuardBG); + // if any carbs have been entered recently if (meal_data.carbs) { // average the minIOBPredBG and minUAMPredBG if available + /* if ( minUAMPredBG < 999 ) { avgMinPredBG = round( (minIOBPredBG+minUAMPredBG)/2 ); } else { avgMinPredBG = minIOBPredBG; } + */ // if UAM is disabled, use max of minIOBPredBG, minCOBPredBG if ( ! enableUAM && minCOBPredBG < 999 ) { @@ -555,12 +572,12 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // if we have COB, use minCOBPredBG, or blendedMinPredBG if it's higher } else if ( minCOBPredBG < 999 ) { // calculate blendedMinPredBG based on how many carbs remain as COB - blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*avgMinPredBG; + blendedMinPredBG = fractionCarbsLeft*minCOBPredBG + (1-fractionCarbsLeft)*minUAMPredBG; // if blendedMinPredBG > minCOBPredBG, use that instead minPredBG = round(Math.max(minIOBPredBG, minCOBPredBG, blendedMinPredBG)); // if carbs have been entered, but have expired, use avg of minIOBPredBG and minUAMPredBG } else { - minPredBG = avgMinPredBG; + minPredBG = minUAMPredBG; } // in pure UAM mode, use the higher of minIOBPredBG,minUAMPredBG } else if ( enableUAM ) { From 9ba6bb0a29e731bfd82b5574d25ad21745a20b8d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Fri, 6 Oct 2017 21:54:32 -0700 Subject: [PATCH 126/215] Don't send stale pushovers (#701) * rm smb-suggested.json after pushover to avoid dupes * require enact/smb-suggested.json be <5m old instead --- bin/oref0-pushover.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/oref0-pushover.sh b/bin/oref0-pushover.sh index 4a4602c55..715ab5f23 100755 --- a/bin/oref0-pushover.sh +++ b/bin/oref0-pushover.sh @@ -16,8 +16,8 @@ fi date if find monitor/ -mmin -$SNOOZE | grep -q pushover-sent; then echo "Last pushover sent less than $SNOOZE minutes ago." -elif ! find $FILE -mmin -$SNOOZE | grep -q $FILE; then - echo "$FILE more than $SNOOZE minutes old" +elif ! find $FILE -mmin -5 | grep -q $FILE; then + echo "$FILE more than 5 minutes old" elif ! cat $FILE | egrep "add'l|maxBolus"; then echo "No additional carbs or bolus required." else From 8eec3aae564ff1e058844f8a5542b310585edd92 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 7 Oct 2017 00:26:07 -0700 Subject: [PATCH 127/215] typofix --- bin/oref0-pump-loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 5291d98a2..2adefc7e6 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -466,7 +466,7 @@ function refresh_old_pumphistory { # refresh pumphistory_24h if it's more than 2h old function refresh_old_pumphistory_24h { find settings/ -mmin -120 -size +100c | grep -q pumphistory-24h-zoned \ - || ( echo -n "Old pumphistory-24h, waiting for $upto30s seconds of silence: " && wait_for_silence $upto30 \ + || ( echo -n "Old pumphistory-24h, waiting for $upto30s seconds of silence: " && wait_for_silence $upto30s \ && echo -n Old pumphistory-24h refresh \ && openaps report invoke settings/pumphistory-24h.json settings/pumphistory-24h-zoned.json 2>&1 >/dev/null | tail -1 && echo ed ) } From ff47d4615f44694ac4b8240e2a93400a8a51c159 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sat, 7 Oct 2017 08:45:03 -0700 Subject: [PATCH 128/215] go back to using a 90m minPredBG lookahead for all insulin types (#695) --- lib/determine-basal/determine-basal.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 5e76bbdc4..820990670 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -435,19 +435,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if ( IOBpredBG < minIOBGuardBG ) { minIOBGuardBG = round(IOBpredBG); } // set minPredBGs starting when currently-dosed insulin activity will peak - var insulinPeakTime = 75; - if ( profile.insulinPeakTime ) { - insulinPeakTime = profile.insulinPeakTime; - } - if ( profile.curve == "ultra-rapid" && !profile.useCustomPeakTime ) { - insulinPeakTime = 55; - } + // look ahead 60m (regardless of insulin type) so as to be less aggressive on slower insulins + var insulinPeakTime = 60; // add 30m to allow for insluin delivery (SMBs or temps) - insulinPeakTime += 30; + insulinPeakTime = 90; var insulinPeak5m = (insulinPeakTime/60)*12; //console.error(insulinPeakTime, insulinPeak5m, profile.insulinPeakTime, profile.curve); - // wait 80-100 before setting minIOBPredBG + // wait 90m before setting minIOBPredBG if ( IOBpredBGs.length > insulinPeak5m && (IOBpredBG < minIOBPredBG) ) { minIOBPredBG = round(IOBpredBG); } if ( IOBpredBG > maxIOBPredBG ) { maxIOBPredBG = IOBpredBG; } // wait 85-105m before setting COB and 60m for UAM minPredBGs From dc1363bc2b5fbfbc84d49e8d6dc9dde2a758207b Mon Sep 17 00:00:00 2001 From: Dana Lewis Date: Sun, 8 Oct 2017 13:51:19 -0700 Subject: [PATCH 129/215] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 21a513ae7..e810ce06d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oref0", - "version": "0.6.0-dev", + "version": "0.6.0-dev1", "description": "openaps oref0 reference implementation of the reference design", "scripts": { "test": "make test", From 0fa1e00b79c18af2c873f4582fe236cd10a8bb31 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 8 Oct 2017 16:27:37 -0700 Subject: [PATCH 130/215] Exercise mode (#684) * set exercise mode basal and ISF based on temptarget * adjust slightly less, and only if temptarget > 110 * for temptargets > 110, adjust sensitivityRatio and IOB * don't set neutral temp if carbsReq * make sure autosens doesn't use temptarget-adjusted insulin calculations * define var sensitivityRatio * define basal before bg < 39 check * allow exercise mode to be disabled in preferences.json * make temptarget that generates 50% basal configurable * use new formula in calculating IOB too * actually update basal before calculating IOB * Changing variable name and adding more explanation to exercise_mode * Update accordingly * Updates for variable name change * Update variable name --- lib/determine-basal/autosens.js | 2 ++ lib/determine-basal/determine-basal.js | 50 ++++++++++++++++++-------- lib/iob/history.js | 29 ++++++++++++++- lib/profile/index.js | 3 ++ 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/lib/determine-basal/autosens.js b/lib/determine-basal/autosens.js index 5adb6be6f..bb0a58d2c 100644 --- a/lib/determine-basal/autosens.js +++ b/lib/determine-basal/autosens.js @@ -148,6 +148,8 @@ function detectSensitivity(inputs) { avgDelta = avgDelta.toFixed(2); iob_inputs.clock=bgTime; iob_inputs.profile.current_basal = basal.basalLookup(basalprofile, bgTime); + // make sure autosens doesn't use temptarget-adjusted insulin calculations + iob_inputs.profile.temptargetSet = false; //console.log(JSON.stringify(iob_inputs.profile)); //console.error("Before: ", new Date().getTime()); var iob = get_iob(iob_inputs, true, treatments)[0]; diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 820990670..8ed726df0 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -59,15 +59,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } var profile_current_basal = round_basal(profile.current_basal, profile); var basal = profile_current_basal; - if (typeof autosens_data !== 'undefined' ) { - basal = profile.current_basal * autosens_data.ratio; - basal = round_basal(basal, profile); - if (basal != profile_current_basal) { - process.stderr.write("Autosens adjusting basal from "+profile_current_basal+" to "+basal+"; "); - } else { - process.stderr.write("Basal unchanged: "+basal+"; "); - } - } var bg = glucose_status.glucose; if (bg < 39) { //Dexcom is in ??? mode or calibrating @@ -102,10 +93,39 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ return rT; } + var sensitivityRatio; + var normalTarget = 100; // evaluate high/low temptarget against 100, not scheduled basal (which might change) + if ( profile.half_basal_target ) { + var halfBasalTarget = profile.half_basal_exercise_target; + } else { + var halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%) + } + if ( profile.exercise_mode && profile.temptargetSet && target_bg > normalTarget + 10 ) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + //sensitivityRatio = 2/(2+(target_bg-normalTarget)/40); + var c = halfBasalTarget - normalTarget; + sensitivityRatio = c/(c+target_bg-normalTarget); + sensitivityRatio = round(sensitivityRatio,2); + process.stderr.write("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; "); + } else if (typeof autosens_data !== 'undefined' ) { + sensitivityRatio = autosens_data.ratio; + process.stderr.write("Autosens ratio: "+sensitivityRatio+"; "); + } + if (sensitivityRatio) { + basal = profile.current_basal * sensitivityRatio; + basal = round_basal(basal, profile); + if (basal != profile_current_basal) { + process.stderr.write("Adjusting basal from "+profile_current_basal+" to "+basal+"; "); + } else { + process.stderr.write("Basal unchanged: "+basal+"; "); + } + } + // adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120 if (typeof autosens_data !== 'undefined' && profile.autosens_adjust_targets) { if (profile.temptargetSet) { - process.stderr.write("Temp Target set, not adjusting with autosens; "); + //process.stderr.write("Temp Target set, not adjusting with autosens; "); } else { // with a target of 100, default 0.7-1.2 autosens min/max range would allow a 93-117 target range min_bg = round((min_bg - 60) / autosens_data.ratio) + 60; @@ -152,14 +172,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var profile_sens = round(profile.sens,1) var sens = profile.sens; if (typeof autosens_data !== 'undefined' ) { - sens = profile.sens / autosens_data.ratio; + sens = profile.sens / sensitivityRatio; sens = round(sens, 1); if (sens != profile_sens) { - process.stderr.write("sens from "+profile_sens+" to "+sens); + process.stderr.write("ISF from "+profile_sens+" to "+sens); } else { - process.stderr.write("sens unchanged: "+sens); + process.stderr.write("ISF unchanged: "+sens); } - process.stderr.write(" (autosens ratio "+autosens_data.ratio+")"); + //process.stderr.write(" (autosens ratio "+sensitivityRatio+")"); } console.error(""); @@ -694,7 +714,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if (eventualBG < min_bg) { // if eventual BG is below target: rT.reason += "Eventual BG " + convert_bg(eventualBG, profile) + " < " + convert_bg(min_bg, profile); // if 5m or 30m avg BG is rising faster than expected delta - if (minDelta > expectedDelta && minDelta > 0) { + if ( minDelta > expectedDelta && minDelta > 0 && !carbsReq ) { // if naive_eventualBG < 40, set a 30m zero temp (oref0-pump-loop will let any longer SMB zero temp run) if (naive_eventualBG < 40) { rT.reason += ", naive_eventualBG < 40. "; diff --git a/lib/iob/history.js b/lib/iob/history.js index 50cd2eeda..43affeb1e 100644 --- a/lib/iob/history.js +++ b/lib/iob/history.js @@ -217,11 +217,38 @@ function calcTempTreatments (inputs) { if (currentItem.duration > 0) { var currentRate = profile_data.current_basal; - if (!_.isEmpty(profile_data.basalprofile)) { currentRate = basalprofile.basalLookup(profile_data.basalprofile,new Date(currentItem.timestamp)); } + if (typeof profile_data.min_bg !== 'undefined' && typeof profile_data.max_bg !== 'undefined') { + target_bg = (profile_data.min_bg + profile_data.max_bg) / 2; + } + //if (profile_data.temptargetSet && target_bg > 110) { + //sensitivityRatio = 2/(2+(target_bg-100)/40); + //currentRate = profile_data.current_basal * sensitivityRatio; + //} + var sensitivityRatio; + var profile = profile_data; + var normalTarget = 100; // evaluate high/low temptarget against 100, not scheduled basal (which might change) + if ( profile.half_basal_target ) { + var halfBasalTarget = profile.half_basal_exercise_target; + } else { + var halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%) + } + if ( profile.exercise_mode && profile.temptargetSet && target_bg > normalTarget + 10 ) { + // w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44 + // e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6 + var c = halfBasalTarget - normalTarget; + sensitivityRatio = c/(c+target_bg-normalTarget); + //} else if (typeof autosens_data !== 'undefined' ) { + //sensitivityRatio = autosens_data.ratio; + //process.stderr.write("Autosens ratio: "+sensitivityRatio+"; "); + } + if ( sensitivityRatio ) { + currentRate = profile_data.current_basal * sensitivityRatio; + } + var netBasalRate = currentItem.rate - currentRate; if (netBasalRate < 0) { tempBolusSize = -0.05; } else { tempBolusSize = 0.05; } diff --git a/lib/profile/index.js b/lib/profile/index.js index 5b6d41120..3c2210221 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -15,6 +15,8 @@ function defaults ( ) { , rewind_resets_autosens: true // reset autosensitivity to neutral for awhile after each pump rewind , autosens_adjust_targets: true // when autosens detects sensitivity/resistance, also adjust BG target accordingly , adv_target_adjustments: true // lower target automatically when BG and eventualBG are high + , exercise_mode: false // when true, > 110 mg/dL high temp target adjusts sensitivityRatio for exercise_mode. This majorly changes the behavior of high temp targets from before. + , half_basal_exercise_target: 160 // when temptarget is 160 mg/dL *and* exercise_mode=true, run 50% basal at this level (120 = 75%; 140 = 60%) // create maxCOB and default it to 120 because that's the most a typical body can absorb over 4 hours. // (If someone enters more carbs or stacks more; OpenAPS will just truncate dosing based on 120. // Essentially, this just limits AMA as a safety cap against weird COB calculations) @@ -55,6 +57,7 @@ function displayedDefaults () { profile.autosens_min = allDefaults.autosens_min; profile.rewind_resets_autosens = allDefaults.rewind_resets_autosens; profile.adv_target_adjustments = allDefaults.adv_target_adjustments; + profile.exercise_mode = allDefaults.exercise_mode; profile.unsuspend_if_no_temp = allDefaults.unsuspend_if_no_temp; profile.enableSMB_with_bolus = allDefaults.enableSMB_with_bolus; profile.enableSMB_with_COB = allDefaults.enableSMB_with_COB; From 73c69f6a2781e1e0b9d4d64a4275be9af0afe03b Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 8 Oct 2017 16:36:08 -0700 Subject: [PATCH 131/215] fix interpolation to go in the right direction (#703) --- lib/determine-basal/cob.js | 16 +++++++++------- lib/meal/total.js | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/determine-basal/cob.js b/lib/determine-basal/cob.js index 258bee902..529b5305e 100644 --- a/lib/determine-basal/cob.js +++ b/lib/determine-basal/cob.js @@ -67,26 +67,26 @@ function detectCarbAbsorption(inputs) { } } var elapsed_minutes = (bgTime - lastbgTime)/(60*1000); -//if (foundPreMealBG) { console.error(bgTime, lastbgTime, elapsed_minutes); } + //console.error(bgTime, lastbgTime, elapsed_minutes); if(Math.abs(elapsed_minutes) > 8) { // interpolate missing data points lastbg = glucose_data[i-1].glucose; elapsed_minutes = Math.abs(elapsed_minutes); //console.error(elapsed_minutes); while(elapsed_minutes > 5) { - nextbgTime = new Date(lastbgTime.getTime() + 5 * 60*1000); + previousbgTime = new Date(lastbgTime.getTime() - 5 * 60*1000); j++; bucketed_data[j] = []; - bucketed_data[j].date = nextbgTime.getTime(); + bucketed_data[j].date = previousbgTime.getTime(); gapDelta = glucose_data[i].glucose - lastbg; //console.error(gapDelta, lastbg, elapsed_minutes); - nextbg = lastbg + (5/elapsed_minutes * gapDelta); - bucketed_data[j].glucose = Math.round(nextbg); + previousbg = lastbg + (5/elapsed_minutes * gapDelta); + bucketed_data[j].glucose = Math.round(previousbg); //console.error("Interpolated", bucketed_data[j]); elapsed_minutes = elapsed_minutes - 5; - lastbg = nextbg; - lastbgTime = new Date(nextbgTime); + lastbg = previousbg; + lastbgTime = new Date(previousbgTime); } } else if(Math.abs(elapsed_minutes) > 2) { @@ -96,6 +96,7 @@ function detectCarbAbsorption(inputs) { } else { bucketed_data[j].glucose = (bucketed_data[j].glucose + glucose_data[i].glucose)/2; } + //console.error(bucketed_data[j].date) } var currentDeviation; var slopeFromMaxDeviation = 0; @@ -174,6 +175,7 @@ function detectCarbAbsorption(inputs) { ci = Math.max(deviation, currentDeviation/2, profile.min_5m_carbimpact); absorbed = ci * profile.carb_ratio / sens; // and add that to the running total carbsAbsorbed + //console.error("carbsAbsorbed:",carbsAbsorbed,"absorbed:",absorbed,"bgTime:",bgTime,"BG:",bucketed_data[i].glucose) carbsAbsorbed += absorbed; } } diff --git a/lib/meal/total.js b/lib/meal/total.js index 266185343..75a9a160d 100644 --- a/lib/meal/total.js +++ b/lib/meal/total.js @@ -51,7 +51,7 @@ function recentCarbs(opts, time) { var myCarbsAbsorbed = calcMealCOB(COB_inputs).carbsAbsorbed; var myMealCOB = Math.max(0, carbs - myCarbsAbsorbed); mealCOB = Math.max(mealCOB, myMealCOB); - //console.error(myMealCOB, mealCOB, carbs); + //console.error("myMealCOB:",myMealCOB, "mealCOB:",mealCOB, "carbs:",carbs,"myCarbsAbsorbed:",myCarbsAbsorbed); if (myMealCOB < mealCOB) { carbsToRemove += parseFloat(treatment.carbs); } else { From 8453388278c1b2d25e6b4e8f015094374e9c5c4e Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 8 Oct 2017 16:45:37 -0700 Subject: [PATCH 132/215] Time-aware carbsReq (#696) * calculate minutesAboveThreshold and indicate carbsReq by then * only put carbsReq in reason if needed w/in 1h * only pushover for carbs by default; override with last argument * display minutesAboveThreshold if minutesAboveMinBG < 60 * don't use lastIOBpredBG if higher than UAM and COB * use minGuardBG to calculate carbsReq * calculate carbsReq based on threshold and minutesAboveThreshold * ignore last 25% of COB when calculating carbsReq * debugging output * only use minGuardBG when eventualBGs hit floor of 39 * just use naive_eventualBG so as not to double-count COB * don't count the last 30% of COB against carbsReq * don't print m zero temp req'd, just carbsReq w/in * don't print m zero temp req'd, just carbsReq w/in * Revert "don't count the last 30% of COB against carbsReq" This reverts commit e95d29a0f0e45ecb7b8fe7d187eab22697e832e3. * debugging output * debugging output * remove no-longer-needed debugging * debugging output * only alert for carbsReq needed w/in 45m --- bin/oref0-pushover.sh | 7 +++- lib/determine-basal/determine-basal.js | 46 +++++++++++++++++++++----- lib/meal/history.js | 2 +- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/bin/oref0-pushover.sh b/bin/oref0-pushover.sh index 715ab5f23..8886b0a06 100755 --- a/bin/oref0-pushover.sh +++ b/bin/oref0-pushover.sh @@ -5,11 +5,12 @@ USER=$2 FILE=${3-enact/smb-suggested.json} SOUND=${4-none} SNOOZE=${5-15} +ONLYFOR=${6-carbs} #echo "Running: $0 $TOKEN $USER $FILE $SOUND $SNOOZE" if [ -z $TOKEN ] || [ -z $USER ]; then - echo "Usage: $0 [enact/smb-suggested.json] [none] [15]" + echo "Usage: $0 [enact/smb-suggested.json] [none] [15] [carbs|insulin]" exit fi @@ -20,6 +21,10 @@ elif ! find $FILE -mmin -5 | grep -q $FILE; then echo "$FILE more than 5 minutes old" elif ! cat $FILE | egrep "add'l|maxBolus"; then echo "No additional carbs or bolus required." +elif [[ $ONLYFOR =~ "carb" ]] && ! cat $FILE | egrep "add'l"; then + echo "No additional carbs required." +elif [[ $ONLYFOR =~ "insulin" ]] && ! cat $FILE | egrep "maxBolus"; then + echo "No additional insulin required." else curl -s -F "token=$TOKEN" -F "user=$USER" -F "sound=$SOUND" -F "message=$(jq -c "{bg, tick, carbsReq, insulinReq, reason}|del(.[] | nulls)" $FILE) - $(hostname)" https://api.pushover.net/1/messages.json && touch monitor/pushover-sent fi diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 8ed726df0..9a3b69b50 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -382,7 +382,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ acid = Math.max(0, meal_data.mealCOB * csf / aci ); // duration (hours) = duration (5m) * 5 / 60 * 2 (to account for linear decay) console.error("Carb Impact:",ci,"mg/dL per 5m; CI Duration:",round(cid*5/60*2,1),"hours; remaining CI (~2h peak):",round(remainingCIpeak,1),"mg/dL per 5m"); - console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours"); + //console.error("Accel. Carb Impact:",aci,"mg/dL per 5m; ACI Duration:",round(acid*5/60*2,1),"hours"); var minIOBPredBG = 999; var minCOBPredBG = 999; var minUAMPredBG = 999; @@ -479,7 +479,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if (meal_data.mealCOB) { console.error("predCIs (mg/dL/5m):",predCIs.join(" ")); console.error("remainingCIs:",remainingCIs.join(" ")); - console.error("COB:",meal_data.mealCOB,"remainingCItotal/csf:",round(remainingCItotal/csf,2),"remainingCarbs:",round(remainingCarbs,2)); + //console.error("COB:",meal_data.mealCOB,"remainingCItotal/csf:",round(remainingCItotal/csf,2),"remainingCarbs:",round(remainingCarbs,2)); } //,"totalCA:",round(totalCA,2),"remainingCItotal/csf+totalCA:",round(remainingCItotal/csf+totalCA,2)); rT.predBGs = {}; @@ -609,7 +609,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ if (minUAMPredBG < 999) { process.stderr.write(" minUAMPredBG: "+minUAMPredBG); } - console.error(" avgPredBG:",avgPredBG,"COB:",meal_data.mealCOB,"carbs:",meal_data.carbs); + console.error(" avgPredBG:",avgPredBG,"COB:",meal_data.mealCOB,"/",meal_data.carbs); // But if the COB line falls off a cliff, don't trust UAM too much: // use maxCOBPredBG if it's been set and lower than minPredBG if ( maxCOBPredBG > bg ) { @@ -632,9 +632,17 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ rT.reason += ", UAMpredBG " + convert_bg(lastUAMpredBG, profile) } rT.reason += "; "; - var bgUndershoot = target_bg - Math.max( naive_eventualBG, eventualBG, lastIOBpredBG ); + //var bgUndershoot = threshold - Math.min(minGuardBG, Math.max( naive_eventualBG, eventualBG )); + // use naive_eventualBG if above 40, but switch to minGuardBG if both eventualBGs hit floor of 39 + //var carbsReqBG = Math.max( naive_eventualBG, eventualBG ); + var carbsReqBG = naive_eventualBG; + if ( carbsReqBG < 40 ) { + carbsReqBG = Math.min( minGuardBG, carbsReqBG ); + } + var bgUndershoot = threshold - carbsReqBG; // calculate how long until COB (or IOB) predBGs drop below min_bg var minutesAboveMinBG = 240; + var minutesAboveThreshold = 240; if (meal_data.mealCOB > 0 && ( ci > 0 || remainingCIpeak > 0 )) { for (var i=0; i= profile.carbsReqThreshold ) { + console.error("naive_eventualBG:",naive_eventualBG,"bgUndershoot:",bgUndershoot,"zeroTempDuration:",zeroTempDuration,"zeroTempEffect:",zeroTempEffect,"carbsReq:",carbsReq); + if ( carbsReq >= profile.carbsReqThreshold && minutesAboveThreshold <= 45 ) { rT.carbsReq = carbsReq; - rT.reason += carbsReq + " add'l carbs req + " + minutesAboveMinBG + "m zero temp; "; + rT.reason += carbsReq + " add'l carbs req w/in " + minutesAboveThreshold + "m; "; } // don't low glucose suspend if IOB is already super negative and BG is rising faster than predicted if (bg < threshold && iob_data.iob < -profile.current_basal*20/60 && minDelta > 0 && minDelta > expectedDelta) { diff --git a/lib/meal/history.js b/lib/meal/history.js index 4208888ff..c6d5a8e6f 100644 --- a/lib/meal/history.js +++ b/lib/meal/history.js @@ -95,7 +95,7 @@ function findMealInputs (inputs) { } } - if (duplicates > 0) console.error("Removed duplicate bolus/carb entries:" + duplicates); + //if (duplicates > 0) console.error("Removed duplicate bolus/carb entries:" + duplicates); return mealInputs; } From 1a9ea732d5db069a9341084b555224e71f01267d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 8 Oct 2017 19:49:39 -0700 Subject: [PATCH 133/215] if last run wanted to microbolus in <1m, don't wait for BG (#704) --- bin/oref0-pump-loop.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index 2adefc7e6..cabb63dd3 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -532,6 +532,8 @@ function refresh_profile { function wait_for_bg { if grep "MDT cgm" openaps.ini 2>&1 >/dev/null; then echo "MDT CGM configured; not waiting" + elif egrep -q "Waiting 0.[0-9]m to microbolus again." enact/smb-suggested.json; then + echo "Retrying microbolus without waiting for new BG" else echo -n "Waiting up to 4 minutes for new BG: " for i in `seq 1 24`; do From bfbe5890a8daf8b0105c3165a15203db3ea7f9d4 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Thu, 12 Oct 2017 20:39:51 -0700 Subject: [PATCH 134/215] Pumphistory safety checks (#702) * pass the lastTemp in iobArray[0] * move currenttemp logging into lib/determine-basal/determine-basal.js * compare currenttemp to iob_data.lastTemp and cancel temp if they don't match * set neutral basals; check tempModulus * cleanup logging * add deliverAt * add absolute * refresh_smb_temp_and_enact now fails without a fresh pumphistory * round lastTemp.duration * null checks to fix failing tests * disable tempModulus check, as it fails across basal schedule boundaries * comment out duration check: it's erroring every time a temp gets half over * no need to refresh_old_pumphistory any longer, as we always refresh before enacting --- bin/oref0-determine-basal.js | 2 +- bin/oref0-pump-loop.sh | 2 -- lib/determine-basal/determine-basal.js | 36 +++++++++++++++++++++++++- lib/iob/index.js | 11 ++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/bin/oref0-determine-basal.js b/bin/oref0-determine-basal.js index 3156a0ae9..c1ee5464d 100755 --- a/bin/oref0-determine-basal.js +++ b/bin/oref0-determine-basal.js @@ -219,7 +219,7 @@ if (!module.parent) { } console.error(JSON.stringify(glucose_status)); - console.error(JSON.stringify(currenttemp)); + //console.error(JSON.stringify(currenttemp)); //console.error(JSON.stringify(profile)); var tempBasalFunctions = require('oref0/lib/basal-set-temp'); diff --git a/bin/oref0-pump-loop.sh b/bin/oref0-pump-loop.sh index cabb63dd3..f24aec9cf 100755 --- a/bin/oref0-pump-loop.sh +++ b/bin/oref0-pump-loop.sh @@ -45,10 +45,8 @@ smb_main() { && ( preflight || preflight ) \ && if_mdt_get_bg \ && refresh_old_pumphistory_24h \ - && refresh_old_pumphistory \ && refresh_old_profile \ && touch /tmp/pump_loop_enacted -r monitor/glucose.json \ - && refresh_smb_temp_and_enact \ && ( smb_check_everything \ && if (grep -q '"units":' enact/smb-suggested.json); then ( smb_bolus && \ diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 9a3b69b50..6f68256c7 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -183,6 +183,41 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } console.error(""); + // compare currenttemp to iob_data.lastTemp and cancel temp if they don't match + var lastTempAge; + if (typeof iob_data.lastTemp !== 'undefined' ) { + lastTempAge = round(( new Date().getTime() - iob_data.lastTemp.date ) / 60000); // in minutes + } + //console.error("currenttemp:",currenttemp,"lastTemp:",JSON.stringify(iob_data.lastTemp),"lastTempAge:",lastTempAge,"m"); + tempModulus = (lastTempAge + currenttemp.duration) % 30; + console.error("currenttemp:",currenttemp,"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m"); + rT.temp = 'absolute'; + rT.deliverAt = deliverAt; + if ( currenttemp && iob_data.lastTemp && currenttemp.rate != iob_data.lastTemp.rate ) { + rT.reason = "Warning: currenttemp rate "+currenttemp.rate+" != lastTemp rate "+iob_data.lastTemp.rate+" from pumphistory; setting neutral temp of "+basal+"."; + return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + } + if ( currenttemp && iob_data.lastTemp && currenttemp.duration > 0 ) { + // TODO: fix this (lastTemp.duration is how long it has run; currenttemp.duration is time left + //if ( currenttemp.duration < iob_data.lastTemp.duration - 2) { + //rT.reason = "Warning: currenttemp duration "+currenttemp.duration+" << lastTemp duration "+round(iob_data.lastTemp.duration,1)+" from pumphistory; setting neutral temp of "+basal+"."; + //return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + //} + //console.error(lastTempAge, round(iob_data.lastTemp.duration,1), round(lastTempAge - iob_data.lastTemp.duration,1)); + var lastTempEnded = lastTempAge - iob_data.lastTemp.duration + if ( lastTempEnded > 5 ) { + rT.reason = "Warning: currenttemp running but lastTemp from pumphistory ended "+lastTempEnded+"m ago; setting neutral temp of "+basal+"."; + //console.error(currenttemp, round(iob_data.lastTemp,1), round(lastTempAge,1)); + return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + } + // TODO: figure out a way to do this check that doesn't fail across basal schedule boundaries + //if ( tempModulus < 25 && tempModulus > 5 ) { + //rT.reason = "Warning: currenttemp duration "+currenttemp.duration+" + lastTempAge "+lastTempAge+" isn't a multiple of 30m; setting neutral temp of "+basal+"."; + //console.error(rT.reason); + //return tempBasalFunctions.setTempBasal(basal, 30, profile, rT, currenttemp); + //} + } + //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone var bgi = round(( -iob_data.activity * sens * 5 ), 2); // project deviations for 30 minutes @@ -251,7 +286,6 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var threshold = min_bg - 0.5*(min_bg-40); //console.error(reservoir_data); - var deliverAt = new Date(); rT = { 'temp': 'absolute' diff --git a/lib/iob/index.js b/lib/iob/index.js index 58ed3563c..200025bfd 100644 --- a/lib/iob/index.js +++ b/lib/iob/index.js @@ -24,12 +24,22 @@ function generate (inputs, currentIOBOnly, treatments) { var clock = new Date(tz(inputs.clock)); var lastBolusTime = new Date(0).getTime(); //clock.getTime()); + var lastTemp = {}; + lastTemp.date = new Date(0).getTime(); //clock.getTime()); //console.error(treatments[treatments.length-1]); treatments.forEach(function(treatment) { if (treatment.insulin && treatment.started_at) { lastBolusTime = Math.max(lastBolusTime,treatment.started_at); //console.error(treatment.insulin,treatment.started_at,lastBolusTime); + } else if (typeof(treatment.rate) === 'number' && treatment.duration ) { + if ( treatment.date > lastTemp.date ) { + lastTemp = treatment; + lastTemp.duration = Math.round(lastTemp.duration*100)/100; + } + + //console.error(treatment.rate, treatment.duration, treatment.started_at,lastTemp.started_at) } + //console.error(treatment.rate, treatment.duration, treatment.started_at,lastTemp.started_at) //if (treatment.insulin && treatment.started_at) { console.error(treatment.insulin,treatment.started_at,lastBolusTime); } }); var iStop; @@ -48,6 +58,7 @@ function generate (inputs, currentIOBOnly, treatments) { } //console.error(lastBolusTime); iobArray[0].lastBolusTime = lastBolusTime; + iobArray[0].lastTemp = lastTemp; return iobArray; } From d4e92ccb7c3de5cb9d4771adf0e8a863489740c8 Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 13 Oct 2017 21:57:12 -0700 Subject: [PATCH 135/215] rm package-lock.json to avoid merge conflicts --- package-lock.json | 1812 --------------------------------------------- 1 file changed, 1812 deletions(-) delete mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index afb6cade6..000000000 --- a/package-lock.json +++ /dev/null @@ -1,1812 +0,0 @@ -{ - "name": "oref0", - "version": "0.5.5", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "abbrev": { - "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", - "dev": true - }, - "ajv": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", - "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "json-schema-traverse": "0.3.1", - "json-stable-stringify": "1.0.1" - } - }, - "align-text": { - "version": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true, - "requires": { - "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz", - "longest": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" - } - }, - "amdefine": { - "version": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, - "ansi-regex": { - "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", - "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=" - }, - "ansi-styles": { - "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "argparse": { - "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", - "dev": true, - "requires": { - "sprintf-js": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - } - }, - "asn1": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", - "integrity": "sha1-VZvhg3bQik7E2+gId9J4GGObLfc=" - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" - }, - "asynckit": { - "version": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "https://registry.npmjs.org/aws4/-/aws4-1.5.0.tgz", - "integrity": "sha1-Cin/t5wxyecS7rCH6OemS0pW11U=", - "dev": true - }, - "balanced-match": { - "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz", - "integrity": "sha1-PKdrhSQccXC/fZcD57mqdGMAQNQ=", - "optional": true, - "requires": { - "tweetnacl": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" - } - }, - "bl": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz", - "integrity": "sha1-wGt5evCF6gC8Unr8jvzxHeIjIFQ=", - "requires": { - "readable-stream": "1.0.34" - } - }, - "boom": { - "version": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "requires": { - "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" - } - }, - "brace-expansion": { - "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz", - "integrity": "sha1-cZfX6qm4fmSDkOph/GbIRCdCDfk=", - "dev": true, - "requires": { - "balanced-match": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "concat-map": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - } - }, - "builtin-modules": { - "version": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, - "camelcase": { - "version": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "center-align": { - "version": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dev": true, - "optional": true, - "requires": { - "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "lazy-cache": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" - } - }, - "chalk": { - "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" - } - }, - "cliui": { - "version": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "wrap-ansi": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "code-point-at": { - "version": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "requires": { - "delayed-stream": "1.0.0" - } - }, - "commander": { - "version": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" - } - }, - "concat-map": { - "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "core-util-is": { - "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "coveralls": { - "version": "https://registry.npmjs.org/coveralls/-/coveralls-2.11.15.tgz", - "integrity": "sha1-N9NHQ2nWbBTzP6c6nSXO5uCZ/KA=", - "dev": true, - "requires": { - "js-yaml": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", - "lcov-parse": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", - "log-driver": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", - "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "request": "https://registry.npmjs.org/request/-/request-2.75.0.tgz" - }, - "dependencies": { - "assert-plus": { - "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true - }, - "aws-sign2": { - "version": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "bl": { - "version": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", - "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", - "dev": true, - "requires": { - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz" - } - }, - "caseless": { - "version": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", - "dev": true - }, - "combined-stream": { - "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "dev": true, - "requires": { - "delayed-stream": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - } - }, - "delayed-stream": { - "version": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "forever-agent": { - "version": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", - "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", - "dev": true, - "requires": { - "asynckit": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "combined-stream": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz" - } - }, - "hawk": { - "version": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "cryptiles": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "sntp": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" - } - }, - "http-signature": { - "version": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "jsprim": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz", - "sshpk": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.1.tgz" - } - }, - "isarray": { - "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "mime-db": { - "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz", - "integrity": "sha1-wY29fHOl2/b0SgJNwNFloeexw5I=", - "dev": true - }, - "mime-types": { - "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz", - "integrity": "sha1-4HqqnGxrmnyjASxpADrSWjnpKog=", - "dev": true, - "requires": { - "mime-db": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz" - } - }, - "oauth-sign": { - "version": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, - "qs": { - "version": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz", - "integrity": "sha1-zgPF/wk1vB2daanxTL0Y5WjWdiU=", - "dev": true - }, - "readable-stream": { - "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - } - }, - "request": { - "version": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", - "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", - "dev": true, - "requires": { - "aws-sign2": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "aws4": "https://registry.npmjs.org/aws4/-/aws4-1.5.0.tgz", - "bl": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", - "caseless": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "combined-stream": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "extend": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", - "forever-agent": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "form-data": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", - "har-validator": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "hawk": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "http-signature": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "is-typedarray": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "isstream": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "json-stringify-safe": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz", - "node-uuid": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", - "oauth-sign": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "qs": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz", - "stringstream": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "tough-cookie": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "tunnel-agent": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" - } - } - } - }, - "cryptiles": { - "version": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "requires": { - "boom": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" - } - }, - "crypto": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/crypto/-/crypto-0.0.3.tgz", - "integrity": "sha1-RwqBuGvkxe4XrMggeh9TFa4g27A=" - }, - "ctype": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", - "integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8=" - }, - "dashdash": { - "version": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - }, - "dependencies": { - "assert-plus": { - "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "debug": { - "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "requires": { - "ms": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - } - }, - "decamelize": { - "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "deep-is": { - "version": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "diff": { - "version": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", - "dev": true - }, - "ecc-jsbn": { - "version": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, - "requires": { - "jsbn": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz" - } - }, - "error-ex": { - "version": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz", - "integrity": "sha1-5ntD8+gsluo6WE/+4Ln8MyXYAtk=", - "requires": { - "is-arrayish": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" - } - }, - "escape-string-regexp": { - "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", - "dev": true, - "requires": { - "esprima": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "estraverse": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "esutils": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "optionator": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" - } - }, - "esprima": { - "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "estraverse": { - "version": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", - "dev": true - }, - "esutils": { - "version": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "extend": { - "version": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", - "integrity": "sha1-WkdDU7nzNT3dgXbf03uRyDpG8dQ=", - "dev": true - }, - "extsprintf": { - "version": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", - "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" - }, - "fast-deep-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", - "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" - }, - "fast-levenshtein": { - "version": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "find-up": { - "version": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", - "requires": { - "asynckit": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, - "generate-function": { - "version": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true - }, - "generate-object-property": { - "version": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" - } - }, - "getpass": { - "version": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", - "integrity": "sha1-KD/9n8ElaECHUxHBtg6MQBhxEOY=", - "requires": { - "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - }, - "dependencies": { - "assert-plus": { - "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "glob": { - "version": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true, - "requires": { - "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - } - }, - "graceful-fs": { - "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "graceful-readlink": { - "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true - }, - "growl": { - "version": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", - "dev": true - }, - "handlebars": { - "version": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz", - "integrity": "sha1-LORISFBTf5yXqAJtU5m5NcTtTtc=", - "dev": true, - "requires": { - "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "optimist": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "uglify-js": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz" - }, - "dependencies": { - "async": { - "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "source-map": { - "version": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz" - } - } - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", - "dev": true, - "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "commander": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "is-my-json-valid": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - } - }, - "has-ansi": { - "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" - } - }, - "has-flag": { - "version": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.0", - "sntp": "2.0.2" - }, - "dependencies": { - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "requires": { - "hoek": "4.2.0" - } - }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.2.0" - } - } - } - }, - "hoek": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", - "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" - }, - "sntp": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", - "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=", - "requires": { - "hoek": "4.2.0" - } - } - } - }, - "hoek": { - "version": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "hosted-git-info": { - "version": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz", - "integrity": "sha1-C6gdkNouJas0ozLm7HeTbhWYEYs=" - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "1.0.0", - "jsprim": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz", - "sshpk": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.1.tgz" - } - }, - "inflight": { - "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - } - }, - "inherits": { - "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "invert-kv": { - "version": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" - }, - "is-arrayish": { - "version": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-buffer": { - "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz", - "integrity": "sha1-z8hszV3FpS+oBIkRHGkgxFfi2Ys=", - "dev": true - }, - "is-builtin-module": { - "version": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz" - } - }, - "is-fullwidth-code-point": { - "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" - } - }, - "is-my-json-valid": { - "version": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz", - "integrity": "sha1-k27do8o8IR/ZjzstPgjaQ/eykVs=", - "dev": true, - "requires": { - "generate-function": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "generate-object-property": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "jsonpointer": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" - } - }, - "is-property": { - "version": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true - }, - "is-typedarray": { - "version": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-utf8": { - "version": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "isexe": { - "version": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz", - "integrity": "sha1-NvPiLmB1CSD15yQaR2qMakInWtA=", - "dev": true - }, - "isstream": { - "version": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "istanbul": { - "version": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", - "dev": true, - "requires": { - "abbrev": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "escodegen": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "esprima": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "glob": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "handlebars": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz", - "js-yaml": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "nopt": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "once": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", - "which": "https://registry.npmjs.org/which/-/which-1.2.12.tgz", - "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" - }, - "dependencies": { - "async": { - "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "supports-color": { - "version": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", - "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", - "dev": true, - "requires": { - "has-flag": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz" - } - } - } - }, - "jade": { - "version": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", - "dev": true, - "requires": { - "commander": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz" - }, - "dependencies": { - "commander": { - "version": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - }, - "mkdirp": { - "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true - } - } - }, - "jodid25519": { - "version": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", - "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=", - "optional": true, - "requires": { - "jsbn": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz" - } - }, - "js-yaml": { - "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", - "integrity": "sha1-bl/mfYsgXOTSL60Ft3geja3MSzA=", - "dev": true, - "requires": { - "argparse": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "esprima": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz" - } - }, - "jsbn": { - "version": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz", - "integrity": "sha1-ZQmH2g3XT06/WhE3eiqi0nPpff0=", - "optional": true - }, - "json": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/json/-/json-9.0.6.tgz", - "integrity": "sha1-eXLCpaSKQmeNsnMMfCxO5uTiRYU=" - }, - "json-schema": { - "version": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, - "jsonpointer": { - "version": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, - "jsprim": { - "version": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz", - "integrity": "sha1-KnJW9wQSop7jZwqspiWZTE3P8lI=", - "requires": { - "extsprintf": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", - "json-schema": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "verror": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz" - } - }, - "kind-of": { - "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz", - "integrity": "sha1-R11pil5J/15T0U4+cyQp3Iv0z0c=", - "dev": true, - "requires": { - "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz" - } - }, - "lazy-cache": { - "version": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true, - "optional": true - }, - "lcid": { - "version": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz" - } - }, - "lcov-parse": { - "version": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", - "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", - "dev": true - }, - "levn": { - "version": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "type-check": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" - } - }, - "load-json-file": { - "version": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "parse-json": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz" - } - }, - "lodash": { - "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.3.tgz", - "integrity": "sha1-VX7X0qlDjKxf1aQwQ8pgy0VeAfc=" - }, - "lodash.assign": { - "version": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" - }, - "log-driver": { - "version": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", - "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=", - "dev": true - }, - "longest": { - "version": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true - }, - "lru-cache": { - "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" - }, - "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "requires": { - "mime-db": "1.30.0" - } - }, - "minimatch": { - "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", - "dev": true, - "requires": { - "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz" - } - }, - "minimist": { - "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mkdirp": { - "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" - }, - "dependencies": { - "minimist": { - "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } - }, - "mocha": { - "version": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", - "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", - "dev": true, - "requires": { - "commander": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "debug": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "diff": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "glob": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "growl": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "jade": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "to-iso-string": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz" - }, - "dependencies": { - "commander": { - "version": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", - "dev": true - }, - "escape-string-regexp": { - "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", - "dev": true - }, - "glob": { - "version": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", - "dev": true, - "requires": { - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz" - } - }, - "minimatch": { - "version": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", - "dev": true, - "requires": { - "lru-cache": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "sigmund": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz" - } - }, - "supports-color": { - "version": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", - "dev": true - } - } - }, - "mocha-lcov-reporter": { - "version": "https://registry.npmjs.org/mocha-lcov-reporter/-/mocha-lcov-reporter-1.2.0.tgz", - "integrity": "sha1-j3uhUSrhJxYR2SdmnZm2wumfBY8=", - "dev": true - }, - "moment": { - "version": "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz", - "integrity": "sha1-/tlQYGPzaxDwZsi1mhRNf66+HYI=" - }, - "moment-timezone": { - "version": "0.5.11", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.11.tgz", - "integrity": "sha1-m3bAPY71FMfkJJp7vOZJ7tOe8p8=", - "requires": { - "moment": "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz" - } - }, - "ms": { - "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true - }, - "node-uuid": { - "version": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", - "integrity": "sha1-baWhdmjEs91ZYjvaEc9/pMH2Cm8=" - }, - "nopt": { - "version": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "requires": { - "abbrev": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" - } - }, - "normalize-package-data": { - "version": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", - "integrity": "sha1-jZJPFClg4Xd+f/4XBUNjHMfLAt8=", - "requires": { - "hosted-git-info": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz", - "is-builtin-module": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "semver": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "validate-npm-package-license": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz" - } - }, - "number-is-nan": { - "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, - "object-assign": { - "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" - }, - "once": { - "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - } - }, - "optimist": { - "version": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" - }, - "dependencies": { - "minimist": { - "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - }, - "wordwrap": { - "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } - } - }, - "optionator": { - "version": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "fast-levenshtein": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "levn": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "prelude-ls": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "type-check": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" - } - }, - "os-locale": { - "version": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "requires": { - "lcid": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz" - } - }, - "parse-json": { - "version": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz" - } - }, - "path-exists": { - "version": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - } - }, - "path-is-absolute": { - "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-type": { - "version": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "pify": { - "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie": { - "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" - } - }, - "pkg-conf": { - "version": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-1.1.3.tgz", - "integrity": "sha1-N45W1v0T6Iv7b0ol33qD+qvduls=", - "requires": { - "find-up": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "load-json-file": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "symbol": "https://registry.npmjs.org/symbol/-/symbol-0.2.3.tgz" - } - }, - "prelude-ls": { - "version": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "process-nextick-args": { - "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "punycode": { - "version": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" - }, - "read-pkg": { - "version": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "requires": { - "load-json-file": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "normalize-package-data": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", - "path-type": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz" - } - }, - "read-pkg-up": { - "version": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "requires": { - "find-up": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "read-pkg": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz" - } - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "requires": { - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "0.0.1", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - } - }, - "repeat-string": { - "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.83.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", - "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", - "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.1", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "isstream": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "json-stringify-safe": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - }, - "dependencies": { - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" - }, - "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "requires": { - "ajv": "5.2.3", - "har-schema": "2.0.0" - } - }, - "tough-cookie": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", - "requires": { - "punycode": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "5.1.1" - } - }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" - } - } - }, - "require-main-filename": { - "version": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "resolve": { - "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - }, - "right-align": { - "version": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dev": true, - "optional": true, - "requires": { - "align-text": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "semver": { - "version": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" - }, - "share2nightscout-bridge": { - "version": "https://registry.npmjs.org/share2nightscout-bridge/-/share2nightscout-bridge-0.1.5.tgz", - "integrity": "sha1-LoxI32A4bteSgiODDcJ63yR0xNM=", - "requires": { - "request": "2.53.0" - }, - "dependencies": { - "assert-plus": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", - "integrity": "sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=" - }, - "aws-sign2": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", - "integrity": "sha1-xXED96F/wDfwLXwuZLYC6iI/fWM=" - }, - "caseless": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.9.0.tgz", - "integrity": "sha1-t7Zc5r8UE4hlOc/VM/CzDv+pz4g=" - }, - "combined-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", - "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=", - "requires": { - "delayed-stream": "0.0.5" - } - }, - "delayed-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", - "integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=" - }, - "forever-agent": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", - "integrity": "sha1-bQ4JxJIflKJ/Y9O0nF/v8epMUTA=" - }, - "form-data": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz", - "integrity": "sha1-Jvi8JtpkQOKZy9z7aQNcT3em5GY=", - "requires": { - "async": "0.9.2", - "combined-stream": "0.0.7", - "mime-types": "2.0.14" - } - }, - "hawk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-2.3.1.tgz", - "integrity": "sha1-HnMc45RH+h0PbXB/e87r7A/R7B8=", - "requires": { - "boom": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "cryptiles": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "sntp": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" - } - }, - "http-signature": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", - "integrity": "sha1-T72sEyVZqoMjEh5UB3nAoBKyfmY=", - "requires": { - "asn1": "0.1.11", - "assert-plus": "0.1.5", - "ctype": "0.5.3" - } - }, - "mime-db": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz", - "integrity": "sha1-PQxjGA9FjrENMlqqN9fFiuMS6dc=" - }, - "mime-types": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz", - "integrity": "sha1-MQ4VnbI+B3+Lsit0jav6SVcUCqY=", - "requires": { - "mime-db": "1.12.0" - } - }, - "oauth-sign": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.6.0.tgz", - "integrity": "sha1-fb6uRPbKRU4fFoRR1jB0ZzWBPOM=" - }, - "qs": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz", - "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=" - }, - "request": { - "version": "2.53.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.53.0.tgz", - "integrity": "sha1-GAo66St7Y5gC5PlUXdj83rcddgw=", - "requires": { - "aws-sign2": "0.5.0", - "bl": "0.9.5", - "caseless": "0.9.0", - "combined-stream": "0.0.7", - "forever-agent": "0.5.2", - "form-data": "0.2.0", - "hawk": "2.3.1", - "http-signature": "0.10.1", - "isstream": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "json-stringify-safe": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "mime-types": "2.0.14", - "node-uuid": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", - "oauth-sign": "0.6.0", - "qs": "2.3.3", - "stringstream": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "tough-cookie": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "tunnel-agent": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" - } - } - } - }, - "should": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/should/-/should-7.1.1.tgz", - "integrity": "sha1-ZGTEi298Hh8YrASDV4+i3VXCxuA=", - "dev": true, - "requires": { - "should-equal": "0.5.0", - "should-format": "0.3.1", - "should-type": "0.2.0" - }, - "dependencies": { - "should-equal": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-0.5.0.tgz", - "integrity": "sha1-x5fxNfMGf+tp6+zbMGscP+IbPm8=", - "dev": true, - "requires": { - "should-type": "0.2.0" - } - }, - "should-format": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-0.3.1.tgz", - "integrity": "sha1-LLt4JGFnCs5CkrKx7EaNuM+Z4zA=", - "dev": true, - "requires": { - "should-type": "0.2.0" - } - }, - "should-type": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-0.2.0.tgz", - "integrity": "sha1-ZwfvlVKdmJ3MCY/gdTqx+RNrt/Y=", - "dev": true - } - } - }, - "sigmund": { - "version": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "sntp": { - "version": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "requires": { - "hoek": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" - } - }, - "source-map": { - "version": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", - "dev": true, - "optional": true, - "requires": { - "amdefine": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz" - } - }, - "spdx-correct": { - "version": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "requires": { - "spdx-license-ids": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz" - } - }, - "spdx-expression-parse": { - "version": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" - }, - "spdx-license-ids": { - "version": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" - }, - "sprintf-js": { - "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.1.tgz", - "integrity": "sha1-MOGl0ykkSXShr2FREznVla9mOLA=", - "requires": { - "asn1": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "assert-plus": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "bcrypt-pbkdf": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz", - "dashdash": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "ecc-jsbn": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "getpass": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", - "jodid25519": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", - "jsbn": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz", - "tweetnacl": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" - }, - "dependencies": { - "asn1": { - "version": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" - }, - "assert-plus": { - "version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "string-width": { - "version": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "is-fullwidth-code-point": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" - } - }, - "string_decoder": { - "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "stringstream": { - "version": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, - "strip-ansi": { - "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" - } - }, - "strip-bom": { - "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz" - } - }, - "supports-color": { - "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "symbol": { - "version": "https://registry.npmjs.org/symbol/-/symbol-0.2.3.tgz", - "integrity": "sha1-O5hzuKkB5Hxu/iFSajrDcu8ou8c=" - }, - "to-iso-string": { - "version": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", - "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", - "dev": true - }, - "tough-cookie": { - "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", - "requires": { - "punycode": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" - } - }, - "tunnel-agent": { - "version": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=" - }, - "tweetnacl": { - "version": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - }, - "type-check": { - "version": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" - } - }, - "uglify-js": { - "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz", - "integrity": "sha1-RhLAx7qu4rp8SH3kkErhIgefLKg=", - "dev": true, - "optional": true, - "requires": { - "async": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "source-map": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "uglify-to-browserify": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "yargs": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz" - }, - "dependencies": { - "async": { - "version": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", - "dev": true, - "optional": true - }, - "camelcase": { - "version": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true, - "optional": true - }, - "cliui": { - "version": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "optional": true, - "requires": { - "center-align": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "right-align": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "wordwrap": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" - } - }, - "source-map": { - "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", - "dev": true, - "optional": true - }, - "window-size": { - "version": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true, - "optional": true - }, - "wordwrap": { - "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true, - "optional": true - }, - "yargs": { - "version": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "optional": true, - "requires": { - "camelcase": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "cliui": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "decamelize": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "window-size": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" - } - } - } - }, - "uglify-to-browserify": { - "version": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "validate-npm-package-license": { - "version": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "requires": { - "spdx-correct": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "spdx-expression-parse": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz" - } - }, - "verror": { - "version": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", - "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", - "requires": { - "extsprintf": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz" - } - }, - "which": { - "version": "https://registry.npmjs.org/which/-/which-1.2.12.tgz", - "integrity": "sha1-3me15FAmnxlJCe8j7OTr5Bb6EZI=", - "dev": true, - "requires": { - "isexe": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz" - } - }, - "window-size": { - "version": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", - "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" - }, - "wordwrap": { - "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "wrap-ansi": { - "version": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" - } - }, - "wrappy": { - "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xtend": { - "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, - "y18n": { - "version": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" - }, - "yargs": { - "version": "https://registry.npmjs.org/yargs/-/yargs-4.3.2.tgz", - "integrity": "sha1-90mPI59SzkJsYf5vljdpS+lN2LA=", - "requires": { - "camelcase": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "cliui": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "decamelize": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "lodash.assign": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "os-locale": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "pkg-conf": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-1.1.3.tgz", - "read-pkg-up": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "require-main-filename": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "string-width": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "window-size": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", - "y18n": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "yargs-parser": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz" - } - }, - "yargs-parser": { - "version": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", - "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", - "requires": { - "camelcase": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "lodash.assign": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz" - }, - "dependencies": { - "camelcase": { - "version": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - } - } - } - } -} From 2f3311629931f8bb8669af934eb75a8a629b97a1 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 15 Oct 2017 12:14:31 -0700 Subject: [PATCH 136/215] fix remaining references to half_basal_target (#712) * fix remaining reference to half_basal_target * fix remaining reference to half_basal_target --- lib/determine-basal/determine-basal.js | 2 +- lib/iob/history.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 6f68256c7..e1bcdda6d 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -95,7 +95,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ var sensitivityRatio; var normalTarget = 100; // evaluate high/low temptarget against 100, not scheduled basal (which might change) - if ( profile.half_basal_target ) { + if ( profile.half_basal_exercise_target ) { var halfBasalTarget = profile.half_basal_exercise_target; } else { var halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%) diff --git a/lib/iob/history.js b/lib/iob/history.js index 43affeb1e..72d82f99d 100644 --- a/lib/iob/history.js +++ b/lib/iob/history.js @@ -231,7 +231,7 @@ function calcTempTreatments (inputs) { var sensitivityRatio; var profile = profile_data; var normalTarget = 100; // evaluate high/low temptarget against 100, not scheduled basal (which might change) - if ( profile.half_basal_target ) { + if ( profile.half_basal_exercise_target ) { var halfBasalTarget = profile.half_basal_exercise_target; } else { var halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%) From 60e6dd5ed7055c381a6a2f0a96fcf77cc5ba8130 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 16 Oct 2017 16:36:19 -0700 Subject: [PATCH 137/215] raise SMB-disable threshold to > 20% of bg to catch fast carb rises (#717) --- lib/determine-basal/determine-basal.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index e1bcdda6d..67e0aa29e 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -714,9 +714,9 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ //rT.reason += "minGuardBG "+minGuardBG+"<"+threshold+": SMB disabled; "; enableSMB = false; } - if ( glucose_status.delta > 0.1 * bg ) { - console.error("Delta",glucose_status.delta,"> 10% of BG",bg,"- disabling SMB"); - rT.reason += "Delta "+glucose_status.delta+" > 10% of BG "+bg+": SMB disabled; "; + if ( glucose_status.delta > 0.20 * bg ) { + console.error("Delta",glucose_status.delta,"> 20% of BG",bg,"- disabling SMB"); + rT.reason += "Delta "+glucose_status.delta+" > 20% of BG "+bg+": SMB disabled; "; enableSMB = false; } From 8017b9c4e627f40043d41fba036d3dbe80ff9f0f Mon Sep 17 00:00:00 2001 From: infoneo Date: Tue, 17 Oct 2017 04:46:33 +0200 Subject: [PATCH 138/215] BlueZ update - min version 5.47 due (BlueBorne vulnerability fix) (#724) https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-1000250 http://www.bluez.org/release-of-bluez-5-47/ --- bin/oref0-setup.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index b4ea5ae4b..c7ed6d3c9 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -636,12 +636,12 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then # Install Bluez for BT Tethering echo Checking bluez installation bluetoothdversion=$(bluetoothd --version || 0) - bluetoothdminversion=5.37 + bluetoothdminversion=5.47 bluetoothdversioncompare=$(awk 'BEGIN{ print "'$bluetoothdversion'"<"'$bluetoothdminversion'" }') if [ "$bluetoothdversioncompare" -eq 1 ]; then killall bluetoothd &>/dev/null #Kill current running version if its out of date and we are updating it - cd $HOME/src/ && wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.44.tar.gz && tar xvfz bluez-5.44.tar.gz || die "Couldn't download bluez" - cd $HOME/src/bluez-5.44 && ./configure --enable-experimental --disable-systemd && \ + cd $HOME/src/ && wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.47.tar.gz && tar xvfz bluez-5.47.tar.gz || die "Couldn't download bluez" + cd $HOME/src/bluez-5.47 && ./configure --enable-experimental --disable-systemd && \ make && sudo make install && sudo cp ./src/bluetoothd /usr/local/bin/ || die "Couldn't make bluez" oref0-bluetoothup else From baefa5d3c7286bb2ddad187eb5f5ec37612e870d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 16 Oct 2017 19:47:35 -0700 Subject: [PATCH 139/215] fix logic fail for ! enableUAM case to set minGuardBG from COB (#721) --- lib/determine-basal/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/determine-basal/determine-basal.js b/lib/determine-basal/determine-basal.js index 67e0aa29e..a6c32d904 100644 --- a/lib/determine-basal/determine-basal.js +++ b/lib/determine-basal/determine-basal.js @@ -590,7 +590,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } // if we have both minCOBGuardBG and minUAMGuardBG, blend according to fractionCarbsLeft - if ( (cid || remainingCIpeak > 0) && enableUAM ) { + if ( (cid || remainingCIpeak > 0) ) { if ( enableUAM ) { minGuardBG = fractionCarbsLeft*minCOBGuardBG + (1-fractionCarbsLeft)*minUAMGuardBG; } else { From 377814edad8349bd8bc22a630bee10ca1c1325cb Mon Sep 17 00:00:00 2001 From: jaylagorio Date: Mon, 16 Oct 2017 22:47:55 -0400 Subject: [PATCH 140/215] Upload entries from G5 to nightscout (#718) * Update packages.json Add the new script * oref0-upload-entries.json This script uploads new CGM entries to Nightscout. If the network connection is lost for a period of time the entries from the last time the upload was successful (stored in ``entries-last-date.json``) buffer in ``entries-upload.json`` until the next successful upload, at which point the file is deleted. This allows the device to be offline for any number of days and you get all the entries, not just the last 288, once it comes back online. * Rename oref0-upload-entries.json to oref0-upload-entries.sh * Update oref0-setup.sh to support "g5-upload" CGM type * Add the Bash indicator --- bin/oref0-setup.sh | 11 +++++++---- bin/oref0-upload-entries.sh | 30 ++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 bin/oref0-upload-entries.sh diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index c7ed6d3c9..d35fc0718 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -137,8 +137,8 @@ case $i in esac done -if ! [[ ${CGM,,} =~ "g4-upload" || ${CGM,,} =~ "g5" || ${CGM,,} =~ "mdt" || ${CGM,,} =~ "shareble" || ${CGM,,} =~ "xdrip" || ${CGM,,} =~ "g4-local" ]]; then - echo "Unsupported CGM. Please select (Dexcom) G4-upload (default), G4-local-only, G5, MDT or xdrip." +if ! [[ ${CGM,,} =~ "g4-upload" || ${CGM,,} =~ "g5" || ${CGM,,} =~ "g5-upload" || ${CGM,,} =~ "mdt" || ${CGM,,} =~ "shareble" || ${CGM,,} =~ "xdrip" || ${CGM,,} =~ "g4-local" ]]; then + echo "Unsupported CGM. Please select (Dexcom) G4-upload (default), G4-local-only, G5, G5-upload, MDT or xdrip." echo DIR="" # to force a Usage prompt fi @@ -170,7 +170,7 @@ if [[ -z "$DIR" || -z "$serial" ]]; then echocolor "You're using a different model pump. Got it." fi - read -p "What kind of CGM are you using? (e.g., G4-upload, G4-local-only, G5, MDT, xdrip?) Note: G4-local-only will NOT upload BGs from a plugged in receiver to Nightscout: " -r + read -p "What kind of CGM are you using? (e.g., G4-upload, G4-local-only, G5, G5-upload, MDT, xdrip?) Note: G4-local-only will NOT upload BGs from a plugged in receiver to Nightscout: " -r CGM=$REPLY echocolor "Ok, $CGM it is." echo @@ -649,7 +649,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then fi fi # add/configure devices - if [[ ${CGM,,} =~ "g5" ]]; then + if [[ ${CGM,,} =~ "g5" || ${CGM,,} =~ "g5-upload" ]]; then openaps use cgm config --G5 openaps report add raw-cgm/raw-entries.json JSON cgm oref0_glucose --hours "24.0" --threshold "100" --no-raw elif [[ ${CGM,,} =~ "shareble" ]]; then @@ -1000,6 +1000,9 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then (crontab -l; crontab -l | grep -q "killall -g --older-than 30m oref0" || echo '* * * * * ( killall -g --older-than 30m openaps; killall -g --older-than 30m oref0-pump-loop; killall -g --older-than 30m openaps-report )') | crontab - # kill pump-loop after 5 minutes of not writing to pump-loop.log (crontab -l; crontab -l | grep -q "killall -g --older-than 5m oref0" || echo '* * * * * find /var/log/openaps/pump-loop.log -mmin +5 | grep pump && ( killall -g --older-than 5m openaps; killall -g --older-than 5m oref0-pump-loop; killall -g --older-than 5m openaps-report )') | crontab - + if [[ ${CGM,,} =~ "g5-upload" ]]; then + (crontab -l; crontab -l | grep -q "oref0-upload-entries" || echo "* * * * * cd $directory && oref0-upload-entries" ) | crontab - + fi if [[ ${CGM,,} =~ "shareble" || ${CGM,,} =~ "g4-upload" ]]; then (crontab -l; crontab -l | grep -q "cd $directory-cgm-loop && ps aux | grep -v grep | grep -q 'openaps monitor-cgm'" || echo "* * * * * cd $directory-cgm-loop && ps aux | grep -v grep | grep -q 'openaps monitor-cgm' || ( date; openaps monitor-cgm) | tee -a /var/log/openaps/cgm-loop.log; cp -up monitor/glucose-raw-merge.json $directory/cgm/glucose.json ; cp -up $directory/cgm/glucose.json $directory/monitor/glucose.json") | crontab - elif [[ ${CGM,,} =~ "xdrip" ]]; then diff --git a/bin/oref0-upload-entries.sh b/bin/oref0-upload-entries.sh new file mode 100644 index 000000000..d98d0ad5d --- /dev/null +++ b/bin/oref0-upload-entries.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +echo "Checking entries-last-date.json..." +if [ -e upload/entries-last-date.json ]; then + LAST_TIME=$(jq -s ".[0].date" upload/entries-last-date.json) + echo "LAST_TIME is $LAST_TIME" + if [ "$LAST_TIME" == "null" ]; then + echo "Setting LAST_TIME to 0" + LAST_TIME=0 + fi +else + echo "Setting LAST_TIME to 0" + LAST_TIME=0 +fi + +echo "Merging cgm-glucose.json and entries-upload.json" +jq -s --unbuffered "[.[0][]] + [.[1][]]|unique|reverse" cgm/cgm-glucose.json upload/entries-upload.json > upload/entries-upload.new.json + +echo "Selecting only those records newer than $LAST_TIME" +jq -s --unbuffered --arg lasttime "$LAST_TIME" '.[0][] | select(.date > ("\($lasttime)" | tonumber))' upload/entries-upload.new.json > upload/entries-upload.array.json + +echo "Merging to an array and removing intermediate files" +jq -s --unbuffered "[.[]]" upload/entries-upload.array.json > upload/entries-upload.json +rm upload/entries-upload.new.json upload/entries-upload.array.json + +UPLOAD_COUNT=$(jq -s ".[]|length" upload/entries-upload.json) +echo "Entries to upload: $UPLOAD_COUNT" +if (( $UPLOAD_COUNT )); then + (ns-upload $NIGHTSCOUT_HOST $API_SECRET entries upload/entries-upload.json - && jq -s "{\"date\":.[0][0].date}" upload/entries-upload.json > upload/entries-last-date.json && rm upload/entries-upload.json) +fi diff --git a/package.json b/package.json index e810ce06d..1f56ab393 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "oref0-subg-ww-radio-parameters": "./bin/oref0-subg-ww-radio-parameters.sh", "oref0_subg_ww_radio_parameters.py": "./bin/oref0_subg_ww_radio_parameters.py", "oref0-truncate-git-history": "bin/oref0-truncate-git-history.sh", + "oref0-upload-entries": "./bin/oref0-upload-entries.sh", "oref0-upload-profile": "./bin/oref0-upload-profile.js", "peb-urchin-status": "./bin/peb-urchin-status.sh", "wifi": "./bin/oref0-tail-wifi.sh" From 3de1f8809a19707daad40faa87e54cb49df93b81 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 16 Oct 2017 19:49:02 -0700 Subject: [PATCH 141/215] Eliminate basal vs. bolus distinctions (#685) * remove all explicit references to basaliob * add enableSMB_always preference, but don't add to displayedDefaults yet * comment out all bolus snooze code * comment out bolus snooze / IOB code * comment out bolus snooze code * comment out bolus snooze code * comment out bolus snooze code * remove bolus snooze code * comment out bolus snooze code * comment out bolus snooze test * uncomment eventualBG < max_bg code and remove snoozeBG * comment out bolus snooze tests * rate <=0 * no more need to track hightempinsulin * no more need to track netbasalinsulin * no more need to track microBolus(IOB|Insulin) * remove one more bolus snooze reference * re-add basaliob and netbasalinsulin etc. --- bin/oref0-html.js | 4 +- bin/oref0-pebble.js | 3 +- bin/oref0-setup.sh | 29 +++--- bin/peb-urchin-status.sh | 4 +- lib/determine-basal/determine-basal.js | 85 ++++++++-------- lib/iob/calculate.js | 6 +- lib/iob/total.js | 76 +++++---------- lib/profile/index.js | 2 - tests/determine-basal.test.js | 77 ++++++++------- tests/iob.test.js | 130 ++++++++++++------------- 10 files changed, 193 insertions(+), 223 deletions(-) diff --git a/bin/oref0-html.js b/bin/oref0-html.js index f05e01ac7..43a930685 100755 --- a/bin/oref0-html.js +++ b/bin/oref0-html.js @@ -135,7 +135,7 @@ if (!module.parent) { //console.log("