Christopher Renshaw Notes

Field note · Healthcare · BLE

Streaming Dexcom G6 to Android: backfill, auth, and the 5-minute cadence.

The Dexcom G6 is a great sensor and a picky BLE peripheral. Treat it like a stock-standard GATT device and you'll lose readings, miss the auth handshake, or get stuck waiting for a measurement that's actually five minutes away. Here's the integration shape we used at Level2 — UnitedHealth Group's Type 2 diabetes platform — to ship clinical-grade glucose streaming with no data loss.

The protocol shape

A G6 transmitter exposes a vendor-specific service rather than the SIG-defined CGM Service (0x181F). The service UUID and its three relevant characteristics are public knowledge from the xDrip+ project:

You scan with a service-UUID filter on the comm service. Once you connect, the dance is: discover services → request MTU → authenticate → enable notifications → request backfill → live notify every 5 minutes.

Authentication is mandatory

Before the transmitter will tell you anything useful, it expects a cryptographic challenge bound to the transmitter's serial number (printed on the sensor packaging — six or seven alphanumeric characters). The flow, per the publicly documented G5/G6 protocol:

  1. App writes an 8-byte authentication request to the Auth characteristic.
  2. Transmitter responds with an 8-byte challenge.
  3. App returns AES-128-ECB of the challenge, using a 16-byte key derived from the serial number.
  4. Transmitter writes status=ok back, or disconnects.

Skip this and your setCharacteristicNotification(measurement, true) will silently never fire. Worst possible failure mode for a clinical product — looks fine in QA, no alarms in production, just zero data.

Backfill: the burst before the cadence

Once authenticated, the very first thing you do is ask the transmitter for backfill. The G6 holds about three hours of historical EGV (Estimated Glucose Value) records on-device. On connect, you ask for everything since your last persisted sequence number and the transmitter blasts you 24-ish 9-byte records in a few hundred milliseconds, one per BLE notification.

// Skeleton — actual record parsing omitted.
suspend fun backfillSince(lastSeq: Int): List<EgvRecord> = withConnection { gatt ->
    val req = BackfillRequest(lastSeq, lookbackMinutes = 180)
    gatt.writeCharacteristic(controlChar, req.encode())

    // Drain backfill notifications until we get the terminator.
    val records = mutableListOf<EgvRecord>()
    backfillNotifications
        .takeWhile { !it.isTerminator() }
        .collect { records += EgvRecord.parse(it.value) }

    db.insertAll(records.distinctBy { it.seq })
    records
}

Two non-obvious things:

The 5-minute live cadence

After backfill, you sit on the live measurement notification. One reading, every five minutes — not five seconds. That cadence is fixed by the sensor hardware. Anyone showing you a Dexcom log with sub-minute reads is showing you a backfill burst, a simulator, or someone else's data.

What this means for the app:

Offline-first is non-negotiable

Level2 patients carried the app to grocery stores, on flights, into elevators, into rural areas. The cloud backend wasn't allowed to be the source of truth. Reading flow:

  1. BLE notification arrives → parse → write to Room (egv_readings table).
  2. WorkManager job, constrained on network, syncs unsent rows to the backend.
  3. UI binds to a Room Flow, not the network. Network is purely a sink.

This is the boring, obvious answer. It's also the one a surprising number of healthcare apps don't ship. The shape that matters: the BLE callback never blocks on the network. Persist locally, return immediately, let WorkManager handle the rest.

Failure modes worth handling

Bottom line

Treat the G6 as what it is: a sensor with a mandatory auth handshake, a one-shot backfill on connect, and a strict 5-minute live cadence. Persist by sequence number, do all I/O off the BLE callback, and assume the network isn't there. Get those four things right and the rest of the integration is just data plumbing.

By Christopher Renshaw — Senior Mobile Software Engineer. Mobile Lead Developer at UnitedHealth Group R&D (2017 – 2020) for Level2, the Type 2 diabetes platform that shipped to 230,000+ members across 27 states.

Hire me for BLE / mobile engineering ↗ All notes ↗