bleCharacteristic.canRead() returning false

Hi everyone,

I'm using the ArduinoBLE.h library.

I'm trying to pass information between two Arduino Nano 33 BLE devices over bluetooth. I'm able to connect the two devices and see their local names and MAC addresses. I'm also able to discover the server device attributes from the client device.

bleDevice.connected()
is returning true.

When I call the method
bleCharacteristic.readValue()
on the client device, it returns nothing. When I call the method
bleCharacteristic.canRead()
on the same characteristic object, it returns false.

What can cause bleCharacteristic.canRead() to return false?

What are the properties of the characteristic defined in the peripheral?

Here is the line of code I use to define the characteristic:

BLEByteCharacteristic medName(deviceServiceCharacteristicUuid, BLERead | BLEWrite);

So I believe I'm giving it the properties BLERead and BLEWrite.
deviceServiceCharacteristicUuid is a const char* variable that I assigned the UUID I want the characteristic to have.

BLEByteCharacteristic is only for a single byte, and it doesn't sound like that is what you are trying to have read.

I think it is time for you to post your code.

Alright. I don't have much experience with byte datatypes.

Here's the code I'm running on the server device:

#include <ArduinoBLE.h>

const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6c-d104768a1214";
const char* deviceServiceCharacteristicUuid = "19b10001-e8f2-537e-4f6c-d104768a1214";

BLEService medService(deviceServiceUuid); 
BLEByteCharacteristic medName(deviceServiceCharacteristicUuid, BLERead | BLEWrite);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

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

  BLE.setLocalName("Remi Phone App");
  BLE.setDeviceName("Remi Phone App");
  BLE.setAdvertisedService(medService);
  BLE.addService(medService);
  medName.writeValue(1);
  BLE.advertise();
  
  Serial.println("Remi Phone App Bluetooth Initialized");
  Serial.println(" ");
}

void loop() {
  // put your main code here, to run repeatedly:
  BLEDevice remiWatch = BLE.central();

  if (remiWatch) {
    Serial.println("* Connected to Remi Smartwatch!");
    Serial.println("* Device MAC Address: ");
    Serial.println(remiWatch.address());
    Serial.println(" ");

    byte med;
    unsigned long lastMessage = 0;

    while (remiWatch.connected()) {
      unsigned long now = millis();

      medName.writeValue(1);
      medName.readValue(med);

      if(now - lastMessage >= 1000) {
        lastMessage = now;
        Serial.println(med);
      }
    }
  }
}

And here is the code I'm running on the client device:

#include <ArduinoBLE.h>

const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6c-d104768a1214";
const char* deviceServiceCharacteristicUuid = "19b10001-e8f2-537e-4f6c-d104768a1214";

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

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

  BLE.setLocalName("Remi Smartwatch");
  BLE.setDeviceName("Remi Smartwatch");
  BLE.advertise();
  
  Serial.println("Remi Smartwatch Bluetooth Initialized");
  Serial.println(" ");
}

void loop() {
  // look for the "phone"
  Serial.println("Looking for Peripheral Device");
  BLE.scanForUuid(deviceServiceUuid);
  BLEDevice phone = BLE.available();
  phone.connect();

  // if a peripheral is found begin communicating
  if (phone) {
    // confirm phone device details
    Serial.println("* Phone found!");
    Serial.print("* Phone MAC address: ");
    Serial.println(phone.address());
    Serial.print("* Phone name: ");
    Serial.println(phone.localName());
    Serial.print("* Advertised service UUID: ");
    Serial.println(phone.advertisedServiceUuid());
    Serial.println(" ");
    BLE.stopScan();

    // discover peripheral attributes
    Serial.println("Discovering attributes ...");
    if (phone.discoverAttributes()) {
      Serial.println("Attributes discovered");
    } else {
      Serial.println("Attribute discovery failed!");
      phone.disconnect();
      //return;
    }
    
    byte med;
    BLECharacteristic medName = phone.characteristic(deviceServiceCharacteristicUuid);
    unsigned long  lastMessage = 0;

    while (phone.connected()) {
      // Request information from the peripheral
      
      medName.readValue(med);
      unsigned long now = millis();

      if (now - lastMessage >= 1000) {
        lastMessage = now;
        if(medName.canRead()) {
          Serial.println("Can Read");
        } else {
          Serial.println("Not Reading");        
        }
        Serial.println(med);
      }
    }
  }  
}

I got it working!

It turns out I was missing a line in the server device code calling the addCharacteristic() method for my medService service object.

Here is the functioning server device code:

#include <ArduinoBLE.h>

const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6c-d104768a1214";
const char* deviceServiceCharacteristicUuid = "19b10001-e8f2-537e-4f6c-d104768a1214";

BLEService medService(deviceServiceUuid); 
BLEByteCharacteristic medName(deviceServiceCharacteristicUuid, BLERead | BLEWrite);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

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

  BLE.setLocalName("Remi Phone App");
  BLE.setDeviceName("Remi Phone App");
  BLE.setAdvertisedService(medService);
  medService.addCharacteristic(medName); // this was the crit missing line
  BLE.addService(medService);
  medName.writeValue(1);
  BLE.advertise();
  
  Serial.println("Remi Phone App Bluetooth Initialized");
  Serial.println(" ");
}

void loop() {
  // put your main code here, to run repeatedly:
  BLEDevice remiWatch = BLE.central();

  if (remiWatch) {
    Serial.println("* Connected to Remi Smartwatch!");
    Serial.println("* Device MAC Address: ");
    Serial.println(remiWatch.address());
    Serial.println(" ");

    byte med;
    unsigned long lastMessage = 0;

    while (remiWatch.connected()) {
      unsigned long now = millis();

      medName.writeValue(1);
      medName.readValue(med);

      if(now - lastMessage >= 1000) {
        lastMessage = now;
        Serial.println(med);
      }
    }
  }
}

This outputs the MAC address of the client device it is connected to followed by a steady stream of 1's every second.

Here is the functioning client device code:

#include <ArduinoBLE.h>

const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6c-d104768a1214";
const char* deviceServiceCharacteristicUuid = "19b10001-e8f2-537e-4f6c-d104768a1214";

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

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

  BLE.setLocalName("Remi Smartwatch");
  BLE.setDeviceName("Remi Smartwatch");
  BLE.advertise();
  
  Serial.println("Remi Smartwatch Bluetooth Initialized");
  Serial.println(" ");
}

void loop() {
  // look for the "phone"
  Serial.println("Looking for Peripheral Device");
  BLE.scanForUuid(deviceServiceUuid);
  BLEDevice phone = BLE.available();
  phone.connect();

  // if a peripheral is found begin communicating
  if (phone) {
    // confirm phone device details
    Serial.println("* Phone found!");
    Serial.print("* Phone MAC address: ");
    Serial.println(phone.address());
    Serial.print("* Phone name: ");
    Serial.println(phone.localName());
    Serial.print("* Advertised service UUID: ");
    Serial.println(phone.advertisedServiceUuid());
    Serial.println(" ");
    BLE.stopScan();

    // discover peripheral attributes
    Serial.println("Discovering attributes ...");
    if (phone.discoverAttributes()) {
      Serial.println("Attributes discovered");
    } else {
      Serial.println("Attribute discovery failed!");
      phone.disconnect();
      //return;
    }
    
    byte med;
    BLECharacteristic medName = phone.characteristic(deviceServiceCharacteristicUuid);
/*
    if (!medName) {
      Serial.println("no characteristic");
      return;
    } else if(!medName.canWrite()) {
      Serial.println("not writeable");
      return;
    }
*/    
    unsigned long  lastMessage = 0;

    while (phone.connected()) {
      // Request information from the peripheral
      
      medName.readValue(med);
      unsigned long now = millis();

      if (now - lastMessage >= 1000) {
        lastMessage = now;
        if(medName) {
          Serial.println("Can Read");
        } else {
          Serial.println("Not Reading");        
        }
        Serial.println(med);
      }
    }
  }  
}

This, when it connects and is working properly, outputs the MAC address, local name, and advertised service UUID of the server device, then prints that it has discovered the server device attributes, and finally prints a steady alternating stream of "Can Read" and 1 every second.

These sketches can be run on two Arduino Nano 33 BLE devices to connect them and send information over bluetooth.

Thanks for the help!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.