2025-12-11
TL;DR: I figured out how to extract real-time blood
glucose data from the Dexcom
Follow app. The solution involves running a virtual Android device
under Waydroid and using adb to pull the current glucose
measurement directly out of the UI. I also set up a ntfy.sh server on my VPS so I
can send push notifications to my phone when the sugar measurement is
above or below certain thresholds.
By the way, please don’t rely on this system to keep anyone alive. I built this in a week for fun.
A person I care about has type 1 diabetes (T1D). (From now on I’ll refer to them as The Subject.) T1D is a medical condition where, in their case, the immune system decides to destroy the pancreas. The pancreas is an organ that produces insulin, which is vital for processing sugar. Since T1Ds can’t produce insulin on their own, they need to inject insulin periodically or they die. Fortunately, The Subject has a continuous glucose monitor (CGM) and an automatic insulin pump, which respectively measure their blood glucose level every five minutes and inject small amounts of insulin to compensate for food intake and activity.
The CGM is made by a company called Dexcom, and they have a system in place where the CGM’s data can make it to the web via the user’s phone. Then, the user can choose to share a live feed of their CGM data with trusted people via a phone app called Dexcom Follow. The Subject has chosen to share their CGM data with me, so I can run the Follow app and get notifications when their sugar is outside a safe range. This is important because it allows me to help them recover if their hypo- or hyperglycemic episode incapacitates them or they’re sleeping.
So far, none of this is a problem, except insofar as a chronic autoimmune disorder is problematic. The system mostly works fine and is an acceptable, if annoying, approximation of the real thing. The “problem” is due to my own technology choices and values. You see, fair reader, the Follow app runs on Android, but only on those Android devices that have Google Play Services (GPS) available. I run GrapheneOS on my phone, which doesn’t ship GPS by default but can enable them as a sandboxed app. I have a few apps that I want to be able to run with GPS enabled, but I don’t like the idea of GPS running all the time, so I sequester these apps in their own special profile with GPS enabled. This is fine, but it’s inconvenient to receive the notifications in my main profile, and the GPS profile drains my phone’s battery much more quickly, so I tend to leave it logged out.
What I really want is for the app to not require GPS. But, failing that, I would be happy with a way to get the data out of Dexcom Follow so I can do whatever I want with it. That’s what this project is about.
I have a mostly-working solution to this problem. I set up a system
where a virtual Android device runs on one of my servers in a headless
configuration, and every minute I use adb to
dump the current view as an XML document. The UI element that contains
the latest glucose measurement has a particular location and key in this
document, so I can reliably extract it with xq. Then I feed
the measurement into a Schmitt trigger-style state machine to determine
whether a notification is needed. If so, then the script pushes a
notification to my phone using my own ntfy.sh server.
The script that does most of it is here with sensitive
information replaced with TODOs. As for system setup,
there’s a lot more to it. Here’s an informal list of steps:
adb connection, although it
might not be headless. If you do use Waydroid, be sure to install the
GAPPS image using waydroid init -s GAPPS. For
configuration, it’s fine to run Waydroid in normal GUI mode. The
headless setup is just for convenience.headless backend and a custom socket name
(e.g.,
weston --backend=headless --socket=wayland-waydroid --width=576 --height=1024).WAYLAND_DISPLAY
environment variable to the socket name from the previous step.adb, bash, curl, and
xq and writes all glucose data to
$script_dir/data.csv.At some point I’ll probably wrap all this up into a
systemd service. For now it’s just running in a few panes
under tmux. The hard part of making it into a service is
probably going to be managing multiple processes at the same time.
bash might not be the best choice for that.
My original plan was to intercept traffic between the app and its server to try to reverse-engineer the API. That would have allowed me to run a completely independent client by replicating the app’s behavior. There has been lots of work on this already, but I discarded the idea for three reasons:
mitmproxy,
but this required rooting the device to install
a new root certificate in the system store. Dexcom Follow has root
detection, though, and refused to operate after I completed the cert
installation. I suppose this is defensible behavior, but again
frustrating. I might have been able to root the phone, install the cert,
and then unroot, but meh.I briefly set up a solution where I used adb to dump a
screenshot of the current view. Then I cropped it with ImageMagick and ran OCR with Tesseract to try to extract the
glucose measurement. This worked most of the time but would sometimes
fail in weird ways, which in hindsight isn’t too surprising. Using
adb to dump the view as semantic data rather than pixels
was the final improvement that made the system reliable enough for
normal use.