Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automated "supermicrobolus" delivery of mealtime insulin #262

Closed
scottleibrand opened this Issue Nov 27, 2016 · 7 comments

Comments

Projects
None yet
3 participants
@scottleibrand
Copy link
Contributor

scottleibrand commented Nov 27, 2016

For users with well-tuned ratios (possibly thanks to #261), we may be able to safely use microboluses to minimize post-prandial peaks without creating additional hypo risk, by accelerating delivery of Eating Soon and AMA mealtime insulin (super bolus style) while at the same time running a zero temp long enough to counteract any extra insulin delivered if carb absorption does not materialize.

In order to safely deliver boluses without risk of overdelivery due to accidental repeats, we need to track reservoir volume as well as pumphistory. By checking reservoir volume before querying pumphistory, and then again immediately before a microbolus, we can ensure that no other boluses have been unaccounted for.

We should also verify (from both data sources) that no other boluses have been delivered within the last 5m, and that the total boluses delivered over the last hour do not exceed the max basal rate. Microboluses should not exceed 30 minutes' worth of regularly scheduled basal (i.e. 0.5U for a basal of 1U/hr) every 5 minutes. Each microbolus should not exceed half of the insulin that would ordinarily be delivered via high temp (as adjusted by expectedDelta), such that if 2U of additional insulin is required, it would be delivered as three 0.5U microboluses 5 minutes apart, then 0.2U at 20m, and 0.1U at 25m, unless minDelta drops below expectedDelta at any point.

For any microbolus that would result in eventualBG below target if played out over DIA with no additional carb absorption, a zero temp of sufficient duration to bring eventualBG back up to target should be set before executing the microbolus, so that if the rig loses connectivity to the pump, and BG starts falling, the additional insulin will be withheld before the bolus takes full effect.

In the case of an eating soon mode (low temp target) we would end up microbolusing enough to accelerate any necessary correction insulin and further correct down to the new temp target, while setting a long enough zero temp to eventually correct back up to target. For example, if we had an eventualBG of 120 vs. target of 100 and were recommending a high temp to deliver 0.5U extra insulin, and would need an extra 0.5U to correct down to 80 (for a total of 1U extra insulin needed), we would start with a microbolus of 0.5U, then 0.2U, then 0.1U, as long as minDelta was above expectedDelta.

If no (or insufficient) bolus is delivered when the meal is eaten, then when BG starts to rise ~15m later, we would shortly begin microbolusing up to 0.5U, until eventualBG gets down to target or the BG rise slows. Alternatively, if the low temp target expires or is canceled, we would also want to stop microbolusing and go back to temp basals if the maximum predicted BG gets down below about 160 (target + 60 or so).

This should make AMA much more effective at blunting post-prandial highs by getting insulin active sooner, but may actually result in less risk of severe hypos if the rig loses connectivity just before carb absorption stops and BG stops rising, because a long zero temp will already be set and will eventually cancel out all the extra bolus insulin if no further action is taken.

It is also worth noting that taking this approach would constitute a relaxation of the first safety design constraint of the original OpenAPS reference design, namely that the system cannot issue insulin boluses and only executes temp basals, to avoid the risk of a rig malfunction issuing a command repeatedly and bypassing maximum delivery limits. As already outlined, this microbolus approach would require that the command to be executed by the system be of the form "issue a 0.2U bolus to bring the reservoir volume down to 162.1U", and implemented in a way to guarantee a fresh reservoir volume check, a current pumphistory check, and a fresh bolusing status check before actually executing a bolus. Even with such safety checks, a relaxation of the original design constraint is only appropriate if we judge the system to be safer overall (for example due to improved walk-away hypo safety), limit microbolus operation to mealtimes when the user is fully aware of how the system is operating and prepared to intervene if necessary, and continue to observe the temp-basal-only constraint for overnight and unattended operation.

In addition to hypo safety, we also need to evaluate and test any microbolus algorithm for the possibility of post-prandial low BG due to excessive bolus delivery at mealtime, which could possibly result in a low BG event before all carbs are absorbed, or after carb absorption due to unexpected situations like overestimated carbs, post-meal activity, interrupted meals, etc. As dosing quantities would be determined by the AMA algorithm, which has been demonstrated effective at avoiding post-prandial lows, my main concern would be with a sharp initial meal rise followed by an early end to carb absorption. We would need to test that appropriate max basal settings and the ratios outlined above (30m worth of basal or 1/2 of insulinReq every 5m) are sufficient to prevent that outcome, and adjust them to deliver smaller microboluses over a longer time period if necessary to get outcomes more like we get with temp-basal-based AMA.

@sulkaharo

This comment has been minimized.

Copy link
Collaborator

sulkaharo commented Nov 27, 2016

Is there a pump event that could be used as a semaphore for bolusing to ensure no duplicate boluses are issued between rigs? Can we set the User Events? If we can read and write those, there could be logic where the loop would set a user event 10 seconds before the bolus and then before bolusing check that another loop hasn't also set the event.

@scottleibrand

This comment has been minimized.

Copy link
Contributor Author

scottleibrand commented Nov 27, 2016

I'm not aware of anything that could be used more reliably than the reservoir and bolusing checks, but there could be. Given how long it takes to execute a bolus, and how quickly we can check reservoir volume and bolusing status, and the fact that you can't execute a bolus when another is already running, I don't think there's any way for multiple rigs to execute the same bolus, but we should definitely test that.

If we did want to set a semaphore, we'd ideally want to be able to somehow allow each rig to set a unique identifier, so they could tell the difference between one they set and one set by another rig.

@scottleibrand scottleibrand changed the title Automated microbolus delivery of mealtime insulin Automated "supermicrobolus" delivery of mealtime insulin Dec 4, 2016

@scottleibrand

This comment has been minimized.

Copy link
Contributor Author

scottleibrand commented Dec 4, 2016

The "determine-supermicrobolus" command should output a supermicrobolus.json containing:

  • The temp basal rate (0) and duration (30+ minutes) to set before delivering the microbolus (long enough to bring eventualBG back up to target if we deliver the bolus and carb absorption stops)
  • The expected reservoir volume at which to deliver the microbolus (the reservoir volume from immediately before the last pumphistory run)
  • The timestamp before which the microbolus needs to be sent (the timestamp of the next expected glucose reading)

After receiving new BG data (and enacting a temp recommended by determine-basal if necessary), the command / alias that enacts the supermicrobolus would then need to do the following (quitting out if any command fails):

  • Delete supermicrobolus.json
  • Refresh reservoir.json
  • Refresh pumphistory.json
  • Run determine-supermicrobolus
  • Enact the recommended zero temp, if any (pass supermicrobolus.json to an openaps use pump set_temp_basal report)
  • Read the currently running temp and verify it matches the recommended
  • Read the pump reservoir volume and verify it is with 0.1U of the expected volume
  • Read the pump status and verify it is not bolusing
  • Verify that the supermicrobolus.json is less than 5 minutes old, and that the current time is prior to the timestamp by which the microbolus needs to be sent
  • Administer the supermicrobolus (pass supermicrobolus.json to an openaps use pump bolus report)
  • Delete supermicrobolus.json
@scottleibrand

This comment has been minimized.

Copy link
Contributor Author

scottleibrand commented Dec 5, 2016

Per discussion with @sulkaharo we might want to do a pump model check and only allow SMB mode on pump models we've tested SMB on. We also need to examine the decocare bolus code and the mmeowlink radio code to make sure it doesn't do any automatic retries of bolus commands, as we'll want to do reservoir checks before doing a higher-level retry if a bolus attempt fails.

We'll also need to be very clear around messaging if we develop and release this, as supermicroboluses fundamentally change the safety model, and requires more thoughtful safety engineering to ensure we have sufficient safeguards in place to prevent any overdosing. One thought there would be to define oref0+SMB = oref1. It probably wouldn't make sense to make it an entirely separate code base, but for example we should probably make sure that any instructions for enabling SMB are kept completely separate from the oref0 docs and setup scripts.

@scottleibrand

This comment has been minimized.

Copy link
Contributor Author

scottleibrand commented Dec 6, 2016

@tim2000s comment #261 (comment):

"One thing we can easily do using RileyLink and Loop is check the behaviour when consecutive bolus requests are made. Using the error logging we should be able to see the details of the rejects. Using Loop, I haven't seen re-requests on failed boluses. I like the idea of oref1 as a separator."

@scottleibrand

This comment has been minimized.

Copy link
Contributor Author

scottleibrand commented Feb 7, 2017

This is now being developed under https://github.com/openaps/oref0/tree/smb

We've been running that branch for several weeks now, and it works well for our scenario. If anyone else wants to test it, please start with a pump that's not actually administering insulin, and let us know how it behaves.

@danamlewis

This comment has been minimized.

Copy link
Contributor

danamlewis commented Feb 7, 2017

(Repeating: if/when this becomes something tested more broadly, it will be an advanced feature that is disabled by default; documented clearly; and very clearly part of something like oref1 to help clarify the different guiding principles.)

scottleibrand added a commit that referenced this issue Mar 15, 2017

oref0-pump-loop (#423)
* typofix

* camelCase autotune and use pumpProfile.autosens_max and min (#319)

* camelCase autotune.js and categorize.js

* use pumpProfile.autosens_max and min instead of 20% hard-coded cap

* revert require('../profile/isf');

* camelCase autotuneM(in|ax)

* syntax

* profile/isf function is still isfLookup

* change ISFProfile back to isfProfile to match pumpprofile

* change basalProfile back to basalprofile to match pumpprofile.json

* change ISFProfile back to isfProfile to match pumpprofile

* camelCase pumpHistory to match categorize.js

* change basalProfile back to basalprofile to match pumpprofile.json

* camelCase pumpProfile to match autotune/index.js

* camelCase to match autotune/index.js

* autotuneMin/Max and camelCase fixes

* disable some debugging

* update 20% log statements for basals to reflect autotune min/max

* mmtune a bit more often

* fix start and end date for ns-treatments.json

* leave ISF unchanged if fewer than 5 ISF data points (#322)

* leave ISF unchanged if fewer than 5 ISF data points

* move stuff out of the else block

* output csf as expected by oref0-autotune-recommends-report.sh

* fix ww pump and dexusb with small changes (#323)

* fix blocker bug for ww pumps and for dex usb

* additional upcasing for radio_locale for cli

* Compare lowercase radio_locale to "ww"

* Don't need quotes

* bump version and require oref0@0.3.6 or later

* install jq for autotune

* use pip install rather than cloning (#324)

* pip install git+URL@dev instead of cloning

* sudo pip install

* move openaps dev install out where it belongs

* remove commented code

* bump version and require oref0@0.3.6 or later

* redirect stderr to stdout so we can grep it

* Continue and output a non-autotuned profile if we don't have autotune_data

* support upload of G4 raw data from USB with cgm-loop

* support upload of G4 raw data from USB with cgm-loop

* sudo /etc/init.d/networking

* install bc for g4-raw

* first WIP attempt at supermicrobolus testing for #262

* round

* 3m for now

* bash version of openaps pump-loop (mostly @cjo20's work)

* mmtune; multi-line for readability; remove ;'s

* remove 3 more openaps invokations

* put main() pump-loop at the top for readability

* move config stuff into a function

* implement supermicrobolus in bin/oref0-pump-loop.sh

* cp smb-enacted.json to enacted.json for upload

* only copy smb-enacted.json if updated; don't bolus w/o 0 temp

* don't print old smb-enacted.json

* verify rate matches and duration is > 5m less than smb-suggested.json

* smb zero temp whenever microBolusAllowed and durationReq > 0

* echo -n filenames

* more tweaks

* zero temp up to 100; 120m max

* set lastBolusTime for any size bolus

* some SMBs can be slightly above profile_data.current_basal/2

* only set lastBolusTime for boluses

* print lastBolusAge more often

* debugging

* more tweaks

* cap lowtempimpact at 30 minutes

* don't mmtune every loop

* Temp refresh before invoke enact/smb-suggested.json

* plumbing to pass reservoir_data to determine-basal

* define reservoir_data

* reservoir default: false

* echo echo...

* reservoir.json is not actually json

* set rT.reservoir = reservoir_data;

* if in SMB mode, don't cancel SMB zero temp when eventually in range

* syntax

* clearer Warning on missing reservoir data

* if in SMB mode, don't cancel SMB zero temp for delta < minDelta

* retry smb_check if first attempt fails

* only print last line of mmeowlink-any-pump-comms.py tracebacks

* wait-for-silence before retry

* syntax

* if in SMB mode, don't cancel SMB zero temp for delta < minDelta

* () for 2>&1

* only bolus 1/3 the insulinReq every 5m

* keep profile and autosens up to date when SMBing

* only consider what we're about to bolus for durationReq

* don't set a zero temp if <15m is needed

* if no zero temp is required, allow later code to set a high temp

* only set rT.rate = 0 if we're setting a temp

* reason grammar

* only check rate and duration if rate is suggested

* debug print statement

* don't print 'setting 0m zero temp'

* reason grammar

* reason grammar

* don't fallback to pump-loop on refresh fails

* syntax

* cp smb suggested and enacted files immediately after invoking

* syntax

* round insulinReq

* only fall back to pump-loop if temp is too old

* debug statement

* parentheses

* remove some TODOs

* don't zero temp up to 100, just to temptarget target_bg

* echo -n

* comment out debug jq

* less unnecessary debugging

* less unnecessary debugging

* less unnecessary debugging

* debug output

* -mmin +5 = more than 5m old

* continue if ! smb_old_temp

* less unnecessary debugging

* less unnecessary debugging

* jq --exit-status

* note when Retrying SMB checks

* always display reservoir levels

* grep -v changes exit status; redirect stdout instead. sleep 20s.

* random wait_for_silence

* syntax

* less unnecessary debugging

* zero seconds doesn't work

* less unnecessary debugging

* don't need to sleep when randomizing wait_for_silence

* echo "Waiting for 45s"

* less unnecessary debugging

* print monitor/status.json

* if smb_old_temp && normal pump-loop succeeds, complete SMB pump-loop

* always show last line of stderr when invoking reports

* support xdrip data source for MDI autotune

* don't redirect determine-basal output

* cat monitor/status.json after invoking

* openaps get-settings 2>/dev/null

* support date field in addition to dateString and displayTime

* remove debugging lines

* remove debugging lines

* no need to be as stringent on low carb_ratios for autotune

* use decay historical carbs by currentDeviation if > min_5m_carbimpact

* remove old comments and TODOs I no longer want to do

* check pump clock is within 2m of current time

* check that pumphistory is less than 1m old after refresh

* one-line pump clock output

* checking pump time vs. rig time in oref0-pump-loop instead

* check -120 < pump clock delta < 120

* newlines and spaces are hard

* get clock-zoned.json to print inline?

* put pumphistory check on its own line

* let's require 1m accuracy on pump clock

* use currentDeviation/2 instead of currentDeviation

* display smb-suggested.json reservoir reading

* always include reservoir level

* always include reservoir level

* check smb-suggested reservoir against reservoir.json

* syntax

* make sure reservoir diff isn't negative

* add deliverAt

* smb_verify_suggested

* mmtune after 30s; 200 wait_for_silence attempts

* remove completed TODO

* add reports to oref0-setup

* oref0-pump-loop.sh

* oref0-pump-loop

* future-proof the grep

* the future is now

* need bc for SMB

* killall -g oref0-pump-loop

* This is creating a file oref0-runagain.sh to save interactive setup options to more easily run again.

* This is properly doing a tmp and then later saving it to the directory we created.

* log both public and private IPs

* New tool to sync profile data from OpenAPS to Nightscout (#301)

* New tool to sync profile data from OpenAPS to Nightscout

* Hashing the secret

* Added tool to package.json

* Support both hashed and unhashed api key

* Added --preview support. Code run through js-beautify. Less console logging.

* Fixed bug with parameter checking order, better logging in case of error / success on upload

* Added profile JSON validity checking

* One more check for the downloaded profile

* Updated HAPP treatments parsing (#350)

It may also make sense to look for !(current.timestamp) && current.insulin since I believe HAPP may give you the ability to edit the "Entered by" string (need to confirm that though).

* Autotune dayofweek (#359)

* script for autotuning based on day of week

* +x

* exit on usage

* accept command-line arguments

* cp mmtune.json to mmtune_old.json for mmtune-speedup

* upgrade mmeowlink

* upgrade mmeowlink

* upgrade mmeowlink if older than 0.10.1

* upgrade mmeowlink if older than 0.10.1

* syntax

* repair/reset/truncate cgm-loop git repo too

* repair/reset/truncate cgm-loop git repo too

* 0.3.7 for oref0-pump-loop

* 0.3.7 for oref0-pump-loop

* monitor-pump stdout to /dev/null

* Trying to prioritize one mac address;if fail, try another

* tested and working: disables wifi if it's not working, until BT goes away

* do this in oref0-online instead

* oref0-bluetoothup no longer needs MAC

* kill off old oref0-pump-loops too

* and openaps-report too

* mmtune 25% of the time

* wait for  silence before mmtuning

* Added additonal logic for HAPP Temp basals (#370)

* Added additonal logic for HAPP Temp basals

Needed to change the timestamp and rate to created_at and absolute respectively.

* Update history.js

* Update history.js

* set -o pipefail to preserve false exit statuses when piping

* units

* turn off debugging

* only run oref0-truncate-git-history if not already running

* syntax

* clarify reasons for @danamlewis

* update tests to match reason change

* syntax

* die when something doesn't work

* don't print blank lines from autotune_recommendations.log

* reject captive portal redirects

* turn off debugging

* only run du after truncating

* kill off any existing git operations so we can gc

* clean out any tmp_pack_ stuff from

* re-randomize sleep times each time through

* prep beforehand too

* don't match on 'killall -g oref0-pump-loop'

* refresh_smb_temp_and_enact before pumphistory for faster low-temps

* wait_for_silence 60 if "usedDefault": true

* Add explorer board prompt and auto-port-itize it if so (#381)

* Attempting to add explorer board prompt to setup script to resolve common error and confusion

* Fix bugs. Be awesome.

* Remove a stray -n for readability

* sorts the treatments collection to address #390

* remove largest old git repo from  to avoid filling up /tmp/

* wrong variable

* typo

* oref0-radio-reboot

* oref0-radio-reboot

* oref0-radio-reboot

* wait 5m to reboot; cancel if it recovers by then

* run oref0-radio-reboot in cron two more times before actually rebooting

* /run/nologin only exists for 5m; run every minute

* print extra newlines to clear old spidev5.1 errors faster

* don't extend reboot time every minute

* write cancelation to logfile

* If we're in SMB mode, disable bolus snooze

* only zero-temp for insulin already delivered, to help with intermittent pump comms

* remove U label for line wrapping @ 120m

* comments

* only re-enact SMB temp if smb_verify_enacted fails

* remove duplicate smb_verify_enacted

* smb_suggest if not doing a full smb_enact_temp

* only enact if smb_verify_enacted fails

* echo No smb_enact needed

* let low-temps run until they have 25m left in SMB mode

* simplify last remaining iwconfig

* Revert "let low-temps run until they have 25m left in SMB mode"

This reverts commit d0d41fd.

This was not canceling zero temps still running after COB expired and SMBs stopped.

* add unannounced meal detection to autotune

* use min_5m_carbimpact for 15g lunch after 15g breakfast

Conflicts:
	lib/determine-basal/determine-basal.js

* remove unused send-tempbasal-Azure.js

* version bump to 0.5.0-dev for oref0-pump-loop

* WARNING: supermicrobolus mode is not yet documented or ready for general testing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.