Bespoke CGM phone-call alerts for T1D glycemic control

Posted on Sat, Aug 28, 2021 health tech
I describe how my programmatic alert driven approach has reduced my management time and improved glycemic control. Code is here.

diabetes and data

Type 1 diabetes (T1D) is one of the most data intensive diseases I know of. Those with this chronic condition require insulin therapy and a continuous glucose monitor (CGM) for management decisions. Blood glucose (BG) is highly variable for T1 diabetic - a can of soda can raise it from 80 to 160 in mere seconds and a burst of exercise or excessive exogenous insulin can do the reverse in minutes. Very low BG can be fatal in the near term and large values lead to complications in the long term. Hence it is important to track it closely. CGMs are wearable devices that output serum glucose predictions every 5 or so minutes. It is a prediction and not a direct measurement because it only uses proxy signals from the interstitial fluid (not blood). In a day the number of BG datapoints generated by a CGM are 288 (24*12) and between quarterly doctor visits it is ~26k (3*30*288). Compare this to a typical lab report's single-number, point-in-time measurement.

then and now

Before I got my CGM I would do frequent blood tests - insert the strip, clean your finger, prick, wait a few seconds and dispose the strip . This was inconvenient, especially in the middle of the night. But the flipside of this friction is that I only checked my reading at the most relevant points in the day. The rest of the time I din't worry about my levels and could use my brain cycles on other things in life. Fast forward to my CGM, the Dexcom G6. A marvelous price of technology that would send a BG reading to my phone every 5 minutes, with high/low alerts and trend predictions. I was hooked! Like a stock trader I would check my levels at the checkout line, in the bathroom, when I had trouble falling asleep and even in the middle of conversations. I even built a chrome extension (Sugar Now) so I could track my levels continuously on every computer I had. This created an obsession and anxiety loop. What's worse is that most of my BG lookups had not changed my management decision in any way. My time and sanity, both precious to me were on the line.

doing alerts differently

I realized I needed a system to continuously check my levels and escalate to me only when it needed my attention. In other words, I needed custom alerts I could trust. Dexcom's G6 and Sugarmate apps allow creating alerts for lows and highs. The Dexcom alert even sounds when iOS do-not-disturb (DND) is turned on. But I needed much finer control. Alerts for lows and highs are simply guardrails that prevent you from going off into dangerous territory in either direction. They don't help your BG stay in the center or to catch harbinger trends before they become a crisis.

I wrote a python job to check Dexcom Clarity (CGM datastore) through pydexcom for my BG levels every 5min. It alerts me under the following conditions ONLY:

  • If BG rose quickly even at low values (100-140). This can happen on a high glycemic meal especially on an empty stomach. When alerted I tend to take insulin, walk or do pushups. The idea is to get ahead of potential BG spikes.
if bg.value >= 100 and bg.trend_description in ("rising quickly"):
    last_alerted_at = alert(bg)
elif bg.value >= 120 and bg.trend_description in (
    "rising",
    "rising quickly",
):
  • If BG rose even slightly or worse at moderate values (140-160). Similar reasoning as above.
elif bg.value >= 140 and bg.trend_description in (
      "rising slightly",
      "rising",
      "rising quickly",
  ):
  • If BG was steady or worse at high values (160+). This can happen on mornings after late high carb dinners or on days when I am distracted. When alerted I might exercise vigorously or push out meals. The idea is to bring down the adamant BG plateau.
elif bg.value >= 160 and bg.trend_description in (
    "steady",
    "rising slightly",
    "rising",
    "rising quickly",
):
  • If BG fell too quickly at low values (70-100). This can happen due to excess insulin, when a meal is quickly out of my system or due to intense exercise. When alerted I turn to fruits in the refrigerator. The idea is to avoid upcoming lows.
elif bg.value <= 100 and bg.trend_description in ("falling quickly"):
elif bg.value <= 80 and bg.trend_description in (
      "falling",
      "falling quickly",
  ):
  • If BG fell even slightly or worse at lower values (<80). Similar reasoning as above.
elif bg.value <= 70 and bg.trend_description in (
                "falling slightly",
                "falling",
                "falling quickly",
            ):
  • If BG was steady or worse at even lower values (<60). This can happen after long swims or fasting. When alerted I'll watch my levels closely and eat appropriately to avoid dangerous lows.
elif bg.value <= 60 and bg.trend_description in (
                "steady",
                "falling slightly",
                "falling",
                "falling quickly",
            ):

I make sure that the alerts won't sound more than once in a two hour period. Any subsequent alerts in the next 2 hours are likely related to the same incident. Annoying alerts tend to be ineffective. I am less likely to benefit or stick to this system if the alerts are redundant or false positives. I tuned this alert window based on my personal cost-benefit tolerance. I do not want to be woken up multiple times in the night. At the same time I don't want to sleep with overnight highs or worse miss a low. In practice I find that as long as I attend to the alert the first time it is very likely that I won't be disturbed soon afterward.

the alert experience

How the alerts are surfaced is the most important part. Push notifications don't work for me personally - these are easy to miss. Dexcom's do-not-disturb immune audible alerts are better, but they are too ephemeral to be reliable. Phone calls are ideal - they are hard to ignore, sticky and when emergency mode is set up, they bypass do-not-disturb. I use an exclusive Twilio number for this purpose to call my phone from the program. Here is how the alert shows up. My phone wails loudly for the next 20 seconds; that's hard to ignore! ONLY when I get this call I switch over to Dexcom G6 to check my BG and handle it. Rest of the time I am a calm happy camper. No context switches to check my levels.

setup

Setting up this job is simple. Follow my github repo. If you are stuck feel free to reach out! Each Twilio alert call costs $0.013 to make. The $5 worth of free Twilio credits every month has been plenty for me. I run my job on a tiny reserved EC2 instance, t3a.nano that costs ~ $2 each month. I do not recommend that you use a EC2 spot instance or a home server for availability/reliability reasons. The cost of running this is practically nothing and the setup effort is minimal.

improved results

Even without checking my health stats I was positive this system improved my results because I now attend to relevant BG events as soon as they happen. Comparing my Dexcom Clarity report for a 3m period before and after these alerts shows CGM based average A1C (a.k.a GMI) decreased from 6.4 to 6.1 (report below). There was a 27% increase in time-in-BG < 140. In the average BG-day plot (2nd pic below) the post graph has far fewer out of range values in the night and through the day. Boom! Keep in mind that I have not altered my management strategy in any meaningful way. It is only the alerts that changed - their relevance, salience and promptness.

3m-prior (Dec 2020-Feb 2021) VS 3m-post (Apr 2021-Jun 2021) aggregate stats
3m-prior (Dec 2020-Feb 2021) VS 3m-post (Apr 2021-Jun 2021) average BG day

time saved

In the early days of my CGM use I would check my BG levels every 15m of my waking hours on average. Later this steadied to every 30m, which is 32 times a day. From this T1D forum thread titled How often do you look at your CGM , I see that there are many patients and caregivers check levels every 10-20min. A majority of them seem to check their levels at-least 30 times a day. Some post excerpts below.

I check my watch about every ten minutes, and am very sensitive to the information I receive. - @docslotnick
I check my CGM every 15-30 minutes unless there is some reason I can’t do so. - @Jen
When I am out with friends or doing something social, I might check every hour or so. When I’m at work, I check every 30 minutes or so. - @Katers87
For Liam, we look all day and it plays a huge role in our lives. - @ClaudenDaye
I’d say I generally checked the graph 30 or 40 times per day.. - @bkh

To estimate the number of times I currently check my levels I exported the Twilio call logs. The distribution of the number of custom alerts per day (below) has a median of 2 alerts/day and an average of 2.65 alerts/day. It appears I've rarely had 4+ alerts in the day. In addition to checking the G6 app when I receive these alerts, I do ask the Sugarmate Alexa-skill for my BG out of curiosity a couple of times per day (typically when I wake up and when I go to bed). Now that brings us to 5 times per day (~3 alerts + 2 unprompted checks). Let's double this estimate for good measure; that is 10 checks (an upper-bound). This is still only one-third of the number of checks that me or another average T1D patient used to make.

Histogram of the "number of Twilio alerts per day"

bottomline

The more steady my BG, the better my quality and quantity of life. The fewer times I am alerted, the lesser my mental overhead to manage the condition. Mental bandwidth is a precious commodity for those with chronic conditions. The 5 or so additional minutes I get back in the day adds up quickly. Those 5 minutes I spent thinking about this ailment I could spend on others in my life. Not needing to open the CGM app unprompted has led to a healthier relationship with my phone. Above all, reducing BG lookups by 66% and improving A1C outcomes seems like a no-brainer to me.