To whom it may concern,
My college senior design team and I are working on a project to recieve bluetooth BLE data from a Dexcom G6 transmitter to an arduino nano 33 iot and rebroadcast this data to another arduino nano 33 iot. The intent of the project to to provide a much wider range for the Dexcom transmitter. Is there a way to rebroadcast this data from one arduino to the next? I’ve seen tutorials for a bridge setup but that was with a device connected directly to an analog or digital pin to the board, not a BLE signaled input. I was thinking of somehow setting the BLE input to virtual pins but I’m not sure that’s possible. I have attached the code my team member put together to scan for dexcom devices. On our arduino serial monitor screen, we can see the UUIDs of the Dexcom transmitter. We are just trying to rebroadcast this information and eventually rebroadcast this information through a series of arduinos throughout an entire house. Any help would be greatly appreciated.
-Blynk app on iphone Xr with arduino nano 33 iot
// This code is (ultimately) designed to identify and re-broadcast
// data packets from a Dexcom transmitter to an endpoint such as a
// smartphone or the Dexcom receiver.
//
// 8 Jan 2021 : Initial revision using Arduino examples
// 14 Jan 2021 : Separated code into setup and loop instead of just setup
// 28 Jan 2021 : Realised scan() is a background process, put into setup
// 1 Feb 2021 : Added some basic attribute and characteristic sections
// 2 Feb 2021 : Used Service ID from BT SIG document for Dexcom (0xFEBC)
// 8 Feb 2021 : Can see Dexcom advert for G5 and G6 (can't connect)
// 10 Feb 2021 : need stopScan() to prep transmitter for connection
// 11 Feb 2021 : able to view the discrete UUIDs for characteristics
// 12 Feb 2021 : start of rewrite into discrete functions instead of one loop
// 15 Feb 2021 : working again - really struggled with parameter passing
// 16 Feb 2021 : finally figured out how to read characteristic data
// 17 Feb 2021 : starting integration of peripheral functionality
// include any libraries or functions here
#include <ArduinoBLE.h>
//************************************************************************//
// Variable Declaration //
//************************************************************************//
bool connectFlag = false; // stable BLE connection indicator
bool repeatForever = true; // false = stop after 1 scan, true = repeats
bool initDone = false; // for bypassing peripheral code setup
bool centCon = false; // toggle for turning off repeated messages
byte devCount = 0; // num. of devices found
byte charCount = 0; // characteristics counter
byte descCount = 0; // descriptors counter
byte servCount = 0; // number of services offered
byte charBuf[512]; // characteristic read buffer
byte descBuf[512]; // descriptor read buffer
char periphAddr[18]; // MAC address of advertising peripheral
const byte maxNodeCnt = 16; // maximum num. of BLE devices supported
const char dexcomUUID[5] = "febc"; // Dexcom corporate service ID + null
const char* servDexcomUUID; // services UUID pointer
const uint16_t companyID = {0x00d0}; // mfg data - peripheral code
const uint8_t mfgBuf[2] = {0xdb, 0x03}; // mfg data - peripheral code
float version = 11.0; // version control? What version control?
String periphAddrDB[maxNodeCnt] = {periphAddr}; // (volatile) list of BLE peripherals
BLEDevice central; // globally declared for all functions
BLEDevice peripheral; // globally declared for all functions
BLEService servDexcom; // variable for BLE service
BLECharacteristic charDexcom; // variable for BLE characteristic
BLEDescriptor descDexcom; // variable for BLE descriptor
//************************************************************************//
// Setup //
//************************************************************************//
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // visible connection indicator
Serial.begin(115200); // faster speed loses less messages
while (!Serial); // waits for serial monitor to open
initBluetoothHardware(repeatForever);
scanForPeripheral(dexcomUUID);
}
//************************************************************************//
// Main Loop //
//************************************************************************//
void loop() {
// through a lot of experimentation it seems some BLE functions need to
// be called in the main loop otherwise the 'peripheral' object does not
// propagate the characteristics correctly to subsequent functions. Maybe
// that's just my poor coding abilities but I freely admit I am a hack
peripheral = BLE.available(); // any advertising BLE devices?
if (peripheral) {
if (getPeripheralAttributes(devCount)) { // get BLE general qualities
stopScanningForPeripheral(); // turn off scanner, switch to interrogator
if (connectPeripheral()) { // connect to BLE device
getPeripheralServices(); // get services and characteristics
disconnectPeripheral(); // release device, go to sleep
devCount++; // device added to database RAM
}
if (repeatForever) {
scanForPeripheral(dexcomUUID);
} else {
BLE.end();
while (true); // endless loop
}
}
}
// if (devCount > 0) {
if (true) {
if (!initDone) {
// peripheral not available now so act like one instead, so there
// these are hard-wired settings just for initial testing of P->C connection
// BLE characteristic property bit mask (0x3F : left = msb, right = lsb)
// BLEBroadcast, BLERead, BLEWriteWithoutResponse, BLEWrite, BLENotify, BLEIndicate
BLEService testService0("1800"); // straight outta Compton
BLEUnsignedCharCharacteristic testCharacteristic0("2a00", BLEWriteWithoutResponse | BLENotify);
BLEUnsignedCharCharacteristic testCharacteristic1("2a01", BLENotify);
BLEUnsignedCharCharacteristic testCharacteristic2("2a04", BLENotify);
BLEService testService1("1801");
BLEUnsignedCharCharacteristic testCharacteristic3("2a05", BLEBroadcast);
byte testDescBuf[2] = {0x0, 0x0};
BLEDescriptor testDescriptor0("2902", testDescBuf, sizeof(testDescBuf));
BLEService testService2("f8083532-849e-531c-c594-30f1f86a4ea5");
BLEUnsignedCharCharacteristic testCharacteristic4("f8083533-849e-531c-c594-30f1f86a4ea5", BLERead | BLENotify);
BLEUnsignedCharCharacteristic testCharacteristic5("f8083534-849e-531c-c594-30f1f86a4ea5", BLEBroadcast | BLEWriteWithoutResponse);
BLEUnsignedCharCharacteristic testCharacteristic6("f8083535-849e-531c-c594-30f1f86a4ea5", BLEBroadcast | BLEWriteWithoutResponse | BLENotify);
BLEUnsignedCharCharacteristic testCharacteristic7("f8083536-849e-531c-c594-30f1f86a4ea5", BLERead | BLEWriteWithoutResponse | BLENotify);
BLEUnsignedCharCharacteristic testCharacteristic8("f8083537-849e-531c-c594-30f1f86a4ea5", BLERead);
BLEService testService3("180a");
BLEUnsignedCharCharacteristic testCharacteristic9("2a29", BLERead);
BLEUnsignedCharCharacteristic testCharacteristic10("2a24", BLERead);
BLEUnsignedCharCharacteristic testCharacteristic11("2a26", BLERead);
// BLE.setAdvertisedService(testService0);
// BLE.setAdvertisedService(testService1);
// BLE.setAdvertisedService(testService2);
// BLE.setAdvertisedService(testService3);
testService0.addCharacteristic(testCharacteristic0);
testService0.addCharacteristic(testCharacteristic1);
testService0.addCharacteristic(testCharacteristic2);
testService1.addCharacteristic(testCharacteristic3);
testService2.addCharacteristic(testCharacteristic4);
testService2.addCharacteristic(testCharacteristic5);
testService2.addCharacteristic(testCharacteristic6);
testService2.addCharacteristic(testCharacteristic7);
testService2.addCharacteristic(testCharacteristic8);
testService3.addCharacteristic(testCharacteristic9);
testService3.addCharacteristic(testCharacteristic10);
testService3.addCharacteristic(testCharacteristic11);
testCharacteristic3.addDescriptor(testDescriptor0);
// byte testBuf[8] = {68, 101, 120, 99, 111, 109, 87, 84};
// testCharacteristic0.writeValue(32);
BLE.addService(testService0); // add the service after it has been configured
BLE.addService(testService1); // add the service after it has been configured
BLE.addService(testService2); // add the service after it has been configured
BLE.addService(testService3); // add the service after it has been configured
BLE.setLocalName("Fake Dexcom");
BLE.setManufacturerData(companyID, mfgBuf, sizeof(mfgBuf));
BLE.setAppearance(0x181F);
BLE.setDeviceName("Fake Dexcom");
// BLE.setAdvertisedServiceUuid("febc");
BLE.setConnectable(true);
BLE.advertise();
Serial.println("Advertising enabled");
initDone = true;
}
central = BLE.central();
if (central && !centCon) {
BLE.stopAdvertise();
if (!centCon) {
Serial.println();
Serial.print("Connected to central: ");
Serial.println(central.address());
centCon = true; // toggles to disconnected state
}
}
if (!central && centCon) {
Serial.println("Central disconnected");
centCon = false; // toggles back to connected state
}
}
}
//************************************************************************//
// initBluetoothHardware //
// inputs : continuous loop indicator //
// outputs : nuthin //
//************************************************************************//
void initBluetoothHardware(bool loopFlag) {
// initialize the BLE hardware, tell user about awesome program
BLE.begin();
Serial.println();
Serial.print("Dexcom 2020 - Transmitter Discovery v");
Serial.println(version, 1);
Serial.print("Program set to ");
if (loopFlag) {
Serial.println("run continuously");
} else {
Serial.println("run one loop");
}
}
//************************************************************************//
// scanForPeripheral //
// inputs : UUID pointer to scan for //
// outputs : nuthin //
//************************************************************************//
void scanForPeripheral(const char *peripheralUUID) {
// start looking for BLE peripherals - UUID parameter makes it specific
BLE.scanForUuid(peripheralUUID, false);
}
//************************************************************************//
// stopScanningForPeripheral //
// inputs : nuthin //
// outputs : nuthin //
//************************************************************************//
void stopScanningForPeripheral(void) {
// stop looking for BLE peripheral advertisements
BLE.stopScan();
delay(1);
}
//************************************************************************//
// connectPeripheral //
// inputs : nuthin //
// outputs : connected to device or didn't //
//************************************************************************//
bool connectPeripheral(void) {
// test for a valid and stable BLE connection after starting a scan
bool connectFlag = false;
Serial.print(" Connecting ...");
if (peripheral.connect()) {
digitalWrite(LED_BUILTIN, HIGH);
Serial.println(" connected");
connectFlag = true;
} else {
Serial.println(" failed to connect!");
}
return connectFlag;
}
//************************************************************************//
// disconnectPeripheral //
// inputs : nuthin //
// outputs : nuthin //
//************************************************************************//
void disconnectPeripheral(void) {
// disconnect from a BLE peripheral
peripheral.disconnect();
digitalWrite(LED_BUILTIN, LOW);
Serial.println(" Peripheral disconnected");
}
//************************************************************************//
// getPeripheralAttributes //
// inputs : number of devices found/saved //
// outputs : found unique device or didn't //
//************************************************************************//
bool getPeripheralAttributes(byte devCount) {
// if a unique peripheral exists, display/save all its attributes
bool dupe = false;
String devAddress = peripheral.address();
for (byte d = 0; d < devCount; d++) { // search for a duplicate MAC address
if (periphAddrDB[d] == devAddress) { // if one is found then jump out of
d = devCount; // the loop stop processing, otherwise
dupe = true; // show the attributes and save them thar
}
}
if (!dupe) {
Serial.println();
Serial.print("Found ");
Serial.print(devAddress);
Serial.print(" '");
Serial.print(peripheral.localName());
Serial.print("' 0x");
Serial.println(peripheral.advertisedServiceUuid());
periphAddrDB[devCount] = devAddress;
}
return !dupe;
}
//************************************************************************//
// getPeripheralServices //
// inputs : nuthin //
// outputs : nuthin //
//************************************************************************//
void getPeripheralServices(void) {
// breakout services and characteristics
if (peripheral.discoverAttributes()) { // VERY IMPORTANT - unlocks stuff
Serial.println(" Discovering services and their characteristics:");
servCount = peripheral.serviceCount();
Serial.print(" Number of services found: ");
Serial.println(servCount);
for (int s = 0; s < servCount; s++) {
servDexcom = peripheral.service(s);
Serial.print(" Service ");
Serial.print(s);
Serial.print(": 0x");
Serial.println(servDexcom.uuid());
getPeripheralCharacteristics(); // nested functions, oh baby
}
}
}
//************************************************************************//
// getPeripheralCharacteristics //
// inputs : nuthin //
// outputs : nuthin //
//************************************************************************//
void getPeripheralCharacteristics(void) {
// BLE characteristic property bit mask (0x3F : left = msb, right = lsb)
// BLEBroadcast, BLERead, BLEWriteWithoutResponse, BLEWrite, BLENotify, BLEIndicate
charCount = servDexcom.characteristicCount();
Serial.print(" Number of characteristics found: ");
Serial.println(charCount);
for (int c = 0; c < charCount; c++) {
charDexcom = servDexcom.characteristic(c);
Serial.print(" Characteristic ");
Serial.print(c);
Serial.print(": 0x");
Serial.print(charDexcom.uuid());
Serial.print(" 0x");
Serial.print(charDexcom.properties(), HEX);
if (charDexcom.canRead()) {
Serial.print(" readable!");
charDexcom.read(); // starts a "read cycle request"
word cLen = charDexcom.valueLength(); // 512 bytes is BLE maximum
Serial.print(" [");
Serial.print(cLen);
Serial.print("]");
charDexcom.readValue(charBuf, cLen); // charBuf is declared globally
for (int v = 0; v < cLen; v++) {
Serial.print(" ");
Serial.print(charBuf[v]);
}
} else {
Serial.print(" not readable");
}
if (charDexcom.canSubscribe()) Serial.print(" subscribable!");
if (charDexcom.canWrite()) Serial.print(" writeable!");
Serial.println();
getPeripheralDescriptors();
}
}
//************************************************************************//
// getPeripheralDescriptors //
// inputs : nuthin //
// outputs : nuthin //
//************************************************************************//
void getPeripheralDescriptors(void) {
descCount = charDexcom.descriptorCount();
if (descCount > 0) {
Serial.print(" Number of descriptors found: ");
Serial.println(descCount);
for (int d = 0; d < descCount; d++) {
descDexcom = charDexcom.descriptor(d);
Serial.print(" Descriptor ");
Serial.print(d);
Serial.print(": 0x");
Serial.print(descDexcom.uuid());
descDexcom.read();
word dLen = descDexcom.valueLength();
Serial.print(" [");
Serial.print(dLen);
Serial.print("]");
charDexcom.readValue(descBuf, dLen); // descBuf is declared globally
for (int g = 0; g < dLen; g++) {
Serial.print(" ");
Serial.print(descBuf[g]);
}
Serial.println();
}
}
}