Connecting Arduino Nano BLE to fenix 6x Pro watch

Hi folks,

im trying to connect my heart rate sensor build in my watch (fenix 6x Pro) to my arduino nano ble.

I'm able to use the example "periferal explorer" to search and read the services of the watch with the following code (adapted only to stop when the watch is found --> if (peripheral.localName() == "fenix 6X Pro")):

#include <ArduinoBLE.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting Bluetooth® Low Energy module failed!");

    while (1);
  }

  Serial.println("Bluetooth® Low Energy Central - Peripheral Explorer");

  // start scanning for peripherals
  BLE.scan();
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    // see if peripheral is a fenix 6X Pro
    if (peripheral.localName() == "fenix 6X Pro") {
      // stop scanning
      BLE.stopScan();

      explorerPeripheral(peripheral);

      // peripheral disconnected, we are done
      while (1) {
        // do nothing
      }
    }
  }
}

void explorerPeripheral(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  // read and print device name of peripheral
  Serial.println();
  Serial.print("Device name: ");
  Serial.println(peripheral.deviceName());
  Serial.print("Appearance: 0x");
  Serial.println(peripheral.appearance(), HEX);
  Serial.println();

  // loop the services of the peripheral and explore each
  for (int i = 0; i < peripheral.serviceCount(); i++) {
    BLEService service = peripheral.service(i);

    exploreService(service);
  }

  Serial.println();

  // we are done exploring, disconnect
  Serial.println("Disconnecting ...");
  peripheral.disconnect();
  Serial.println("Disconnected");
}

void exploreService(BLEService service) {
  // print the UUID of the service
  Serial.print("Service ");
  Serial.println(service.uuid());

  // loop the characteristics of the service and explore each
  for (int i = 0; i < service.characteristicCount(); i++) {
    BLECharacteristic characteristic = service.characteristic(i);

    exploreCharacteristic(characteristic);
  }
}

void exploreCharacteristic(BLECharacteristic characteristic) {
  // print the UUID and properties of the characteristic
  Serial.print("\tCharacteristic ");
  Serial.print(characteristic.uuid());
  Serial.print(", properties 0x");
  Serial.print(characteristic.properties(), HEX);

  // check if the characteristic is readable
  if (characteristic.canRead()) {
    // read the characteristic value
    characteristic.read();

    if (characteristic.valueLength() > 0) {
      // print out the value of the characteristic
      Serial.print(", value 0x");
      printData(characteristic.value(), characteristic.valueLength());
    }
  }
  Serial.println();

  // loop the descriptors of the characteristic and explore each
  for (int i = 0; i < characteristic.descriptorCount(); i++) {
    BLEDescriptor descriptor = characteristic.descriptor(i);

    exploreDescriptor(descriptor);
  }
}

void exploreDescriptor(BLEDescriptor descriptor) {
  // print the UUID of the descriptor
  Serial.print("\t\tDescriptor ");
  Serial.print(descriptor.uuid());

  // read the descriptor value
  descriptor.read();

  // print out the value of the descriptor
  Serial.print(", value 0x");
  printData(descriptor.value(), descriptor.valueLength());

  Serial.println();
}

void printData(const unsigned char data[], int length) {
  for (int i = 0; i < length; i++) {
    unsigned char b = data[i];

    if (b < 16) {
      Serial.print("0");
    }

    Serial.print(b, HEX);
  }
}

I get this feedback (thinking that the value of the heart rate sensor still needs to be translated also):

(...)
Service 180d
Characteristic 2a37, properties 0x10
Descriptor 2902, value 0x0000
Service 1814
Characteristic 2a54, properties 0x2, value 0x0000
Descriptor 2803, value 0x103800532A
Descriptor 2a53, value 0x00000000
Characteristic 2a53, properties 0x10
Descriptor 2902, value 0x0000

Disconnecting ...
Disconnected

I would like to subscribe to the heart rate service but don't know how.
I also tried to use this code that i found (Link: ArduinoBLE, can't receive heart rate data! - #2 by J-M-L)

#include <ArduinoBLE.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while (1);
  }

  Serial.println("BLE Central for Polar HR Server");
  BLE.scanForUuid("180D");
}

void loop() {

  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();
    if (peripheral.localName() == "FT7") { //name of simulated Polar HR device
      BLE.stopScan();
      if (peripheral.connect())
        Serial.print("Connedted to FT7 ");
      Serial.println("Discovering attributes ...");
      if (peripheral.discoverAttributes()) { //find services and characterisitics
        Serial.println("Attributes discovered");
        BLEService service = peripheral.service("180d");
        BLECharacteristic characteristic = service.characteristic("2a37");
        characteristic.subscribe();
        Serial.println("subscribed to 2a37");
        
      } else {
        Serial.println("Attribute discovery failed!");
        peripheral.disconnect();
        return;
      }
    }
    else {
      Serial.println("Failed to connect!");
      return;
    }

    while (peripheral)
    {
      BLEService service = peripheral.service("180d");
      BLECharacteristic characteristic = service.characteristic("2a37");
      
      if (characteristic.valueUpdated())
      {
        Serial.println("value updated");
        characteristic.read();     
        printData(characteristic.value(), characteristic.valueLength());
        Serial.println();
      }
      Serial.println();
      delay(1000);
    }
  }
}

void printData(const unsigned char data[], int length) {
  for (int i = 0; i < length; i++) {
    unsigned char b = data[i];

    if (b < 16) {
      Serial.print("0");
    }

    Serial.print(b, HEX);
  }
}

I get this feedback:
Found 90:f1:57:a3:2c:c4 'fenix 6X Pro' 180d
Failed to connect!
Found 90:f1:57:a3:2c:c4 'fenix 6X Pro' 180d
Failed to connect
Found 90:f1:57:a3:2c:c4 'fenix 6X Pro' 180d
Failed to connect!

I would be greatful for help.

With the second code presented, I think that in this block you need to change the localName to that used by your device which seems to be "fenix 6X Pro"

if (peripheral) {
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();
    //if (peripheral.localName() == "FT7") {
       if (peripheral.localName() == "fenix  6X Pro") {

Hi Cattledog,

thanks for your help! I'm sorry, i should have noticed this my self. -.- I get a value now! Can you explain to me how this part works:

void printData(const unsigned char data[], int length) {
  for (int i = 0; i < length; i++) {
    unsigned char b = data[i];

    if (b < 16) {
      Serial.print("0");
    }

    Serial.print(b, HEX);
  }
}

Thanks in advance! : )

void printData(const unsigned char data[], int length) {
  for (int i = 0; i < length; i++) {
    unsigned char b = data[i];

    if (b < 16) {
      Serial.print("0");
    }

    Serial.print(b, HEX);
  }
}

It prints out the bytes of the read data in HEX format with a leading 0 if the value is less than 16.

characteristic.read();     
printData(characteristic.value(), characteristic.valueLength());

You'll have to review the library source files in detail, but I would think that .read() fills a buffer which you access through .value() and its length.

What exactly don't you understand?

characteristic.read();     
printData(characteristic.value(), characteristic.valueLength());

Seems to print per run through the For-loop either the characteristic value or the length value. I only want to get the heart rate value (haracteristic value) but I struggle to get rid of the length value.

I solved it for now by checking of the value is > 6 since a heart rate value should be bigger. But that is not really the propper way I feel like.

I don't understand. The code should be printing out all the bytes received. The heart rate value is carried somewhere within the full data frame. Can you provide and example of what you are seeing?

yes, you are right. i guess its the package that delivers the length value and the heart rate. I just wish i could get rid of the length. Now i just check if the value is > than 6 to just not print it.

void printData(const unsigned char data[], int length) {
  for (int i = 0; i < length; i++) {
    unsigned char b = data[i];

    if (b > 6) {
    Serial.print(b);
    Serial.println(" bpm");
      
      //Turn on blue LED if Heart Rate smaller than 60 bpm
      if (b < 60) {
        //Serial.println();
        Serial.print("blue led on");
        //Serial.println();


        digitalWrite(LEDR, HIGH);       // will turn the LED off
        digitalWrite(LEDG, HIGH);       // will turn the LED off
        digitalWrite(LEDB, LOW);        // will turn the LED on
      }

      if (b >= 60) {
        //Serial.println();
        Serial.print("red led on");
        //Serial.println();


        digitalWrite(LEDR, LOW);        // will turn the LED on
        digitalWrite(LEDG, HIGH);       // will turn the LED off
        digitalWrite(LEDB, HIGH);       // will turn the LED off
      }
    } 

  }
}