This system has two main components: the Arduino code, and the Garmin ConnectIQ app. The Arduino code mainly handles the conversion of analog measurements into a glucose concentration value, and the transmission of that value via BLE. The ConnectIQ app scans and connects to the Arduino, and reads and interprets the glucose values.
This system is intended to work with Garmin Venu series smartwatches, and Arduino boards with the ublox w10 series radio modules.
The system uses the BLE protocol with officially recognized UUIDs for glucose measurement. The structure of the BLE service stack looks like the following:
- Service: Glucose Measurement
00001808-0000-1000-8000-00805F9B34FB- Characteristic: Glucose Concentration
00002A18-0000-1000-8000-00805F9B34FB, with a value field size of 2 bytes and a default value of0x0000.- Descriptor:
CCCDfor asynchronous BLE notifications.
- Descriptor:
- Characteristic: Glucose Concentration
Within the specified characteristic:
- The value
0x0000is reserved to communicate the state "waiting for blood" - The value
0xffffis reserved to communicate the state "blood detected", which is a 5 second interval between blood detection and output generation.
The Arduino board applies a biasing voltage of 400mV between the reference nad working electrodes of a glucose test strip, then measures the voltage output of a transimpedance amplifier connected to the test strip. This output is measured for 5 seconds and the final 4 measured values are averaged. This value is directly proportional to the concentration of glucose on the test strip.
The code has several calibration values defined in the beginning, and these are set according to empirical experiemnts done against a commercially availabel glucometer using control solutions. A linear relationship is established between two different glucose concentrations, and a calibration curve is created to represent this relationship. The Arduino code creates this calibration curve automatically given the calibration values and subsequently uses the curve to convert new raw data into glucose concentration in mg/dL.
The app is written in Monkey C, and mainly takes advantage of Toybox.BluetoothLowEnergy.
A class Foo wishes to connect to the Arduino and access glucose data, therefore it creates an instance of BluetoothFetcher, which extends BleDelegate. During the construction of BluetoothFetcher, Foo passes 2 of its own functions as symbols to enable asynchronous callbacks generated by BLE state change events:
connectionCallbackMethodis called when a connection to a glucometer device is established.glucoseValueCallbackMethodis called when a new glucose concentration value is available.
Once BluetoothFetcher is initialized, Foo needs to attach the delegate to the current BLE session by calling Ble.setDelegate(). Once this is done, Foo simply has to call startScan() on the fetcher class and implement the two callback functions. The BluetoothFetcher class itself will take care of almost all BLE related operations automatically.
- The call to
glucoseValueCallbackMethodwill pass a byte array as parameter. Therefore, this must be treated carefully in the implementation of the callback function. For example, when usingdecodeNumber(), the value must be converted into a 16-bit unsigned integer, and the correct array offset and endianness must be chosen. - When the
scanServiceUUID()method is used,BluetoothFetcherwill not be able to connect to any of the scan results becausescanServiceUUID()consumes the iterator it is given, leaving none for the actual connection portion. - A class containing a
BluetoothFetcherinstance should not call any of the methods reserved for asynchronous BLE callbacks (e.g.onCharacteristicChanged), otherwise unexpected behavior might occur. - The
setGlucoseNotification()method is necessary because it sets the value of the CCCD associated with the glucose characteristic to 1. This allows that specific characteristic to asynchronously notify the app of any changes.
For more information, see detailed comments in the code.