After successful BLE.connect - Cannot read characteristic

Hello,

After a successful BLE.connect() to a BLE device, I am unable to read that device's characteristics. This always returns false:

peer.getCharacteristicByUUID(myChar, BleUuid("4149524C-03B7-0014-0004-000000000000"));

I know the UUID is correct as I have a smartphone app that connects to it and reads it just fine.

Does anyone have any code that can print / enumerate / list all of the services and characteristics on a particular connected peer?

Thanks.

  • Chris

Here is some code I am using to test the connection.

// Turn on all logging
SerialLogHandler 		    logHandler(LOG_LEVEL_ALL);

// Global variables
BleCharacteristic		    ble_char;
const BleUuid               ble_charUuid("4149524C-03B7-0014-0004-000000000000");
BleScanResult               ble_scanResult;
BlePeerDevice               ble_peer;
BleScanResult 			    ble_devices[30];
int			                ble_devices_seen = 0;


// Setup
void setup() {

    // Start logging 
    Log.info("Starting...");

}


// Loop
void loop() {

    // Scan for nearby devices
	ble_devices_seen = BLE.scan(ble_devices, 30);
	Log.info("BLE devices: %u", ble_devices_seen);
	
	// Check each seen device
	for (int x = 0; x < ble_devices_seen; x++) {
       	BleScanResult scanResult = ble_devices[x];
       	
       	// Is this device we are looking for?
       	if (scanResult.address[5] == 0xF4 && scanResult.address[4] == 0x03 && scanResult.address[3] == 0xB7 && 
       	    scanResult.address[2] == 0x62 && scanResult.address[1] == 0xB7 && scanResult.address[0] == 0x86) {
       	    
       	    // Connect to it
	        ble_peer = BLE.connect(scanResult.address);
            if (ble_peer.connected()) {
                Log.info("connected");
                
                // Attempt to read the characteristic
				if (ble_peer.getCharacteristicByUUID(ble_char, ble_charUuid)) {
                    Log.info("read characteristic");
                } else {
                    Log.info("failed to read characteristic");
                }
                
                // Disconnect
                BLE.disconnect(ble_peer);
                Log.info("disconnected");
			} else {
				Log.info("connection failed"); 
			}
		}
	}
	
	// Try every 10 seconds
	delay(10000);
}

This is the serial log output from running the above program:

0000046248 [app] INFO: Starting...
0000072109 [app] INFO: BLE devices: 24
0000072322 [wiring.ble] TRACE: New peripheral is connected.
0000072323 [wiring.ble] TRACE: Start discovering services.
0000072684 [wiring.ble] TRACE: Start discovering characteristics.
0000074844 [app] INFO: connected
0000074944 [app] INFO: failed to read characteristic
0000075114 [app] INFO: disconnected

On the peripheral device, I can see the connection being made, the MTU being negotiated, but I never see a characteristic being read.

Further troubleshooting shows that 2-byte characteristics (such as 0x2A00 - Device name) can be read successfully. I am unable to read 128-bit UUID custom characteristics. All from the same peripheral device.

Not sure why that wouldn't work, but you could investigate the ble_peer.discoverAllCharacteristics() vector to see whether your particular chararcteristic shows up at all (and where the discrepancy may come from).

Can you post a screenshot of the UUID discoverd by your smartphone?

Thanks ScruffR,

This is not a scren shot, but here is the service/characteristic configuration.

UUID (0x1800) - Generic Access Services
  + UUID (0x2A00) - Device name characteristic (19-bytes r)
  + UUID (0x2A01) - Appearance characteristic (2-bytes r)
  + UUID (0x2A04) - Connection parameters characteristic (8-bytes r)
UUID (0x1801) - Generic Attribute Service
  + UUID (0x2A05) - Service changed characteristic (4-bytes r)
UUID (4149524C-03B7-0014-0004-000000000000) - Custom primary service
  + UUID (4149524C-03B7-0014-0004-000000000001) - Status characteristic (128-bytes r)
  + UUID (4149524C-03B7-0014-0004-000000000002) - Command characteristic (20-bytes rw)
  + UUID (4149524C-03B7-0014-0004-000000000003) - Long command characteristic (132-bytes rw)

I will take a look at the vector you suggested and see what data is in there. I assume that the Particle system supports multiple services with multiple characteristics.

Thanks.

I see there is no characteristics that ends on 000000000000 only the service does.
To have getCharacteristicsByUUID() to work with 128bit UUIDs you have to have an exact match.

Ah yes, you were correct. I had the service UUID in there and no the characteristic. Oh well, not all is lost. I wrote some code to scan nearby BLE devices and then read all of the characteristics from a particular one. Maybe someone will find this useful.

// Set the MAC address of the BLE device we want to scan
#define BLE_PEER_ADDRESS    {0x86, 0xB7, 0x62, 0xB7, 0x03, 0xF4}

// Turn on all logging
SerialLogHandler 		    logHandler(LOG_LEVEL_ALL);

// Global variables
Vector<BleCharacteristic>   ble_peer_all_chars;
BleCharacteristic		    ble_char;
char                        ble_char_uuid_string[40];
byte                        ble_char_value[250];
char                        ble_char_value_string[501];
BlePeerDevice               ble_peer;
int                         ble_peer_found_at = -1;
const BleAddress            ble_peer_address = BleAddress(BLE_PEER_ADDRESS);
BleScanResult 			    ble_devices[30];
int			                ble_devices_seen = 0;


// Setup
void setup() {

  // Start logging 
  Log.info("Starting...");
    
}


// Loop
void loop() {

    // Start
    Log.info("Scanning for nearby BLE devices...");

    // Scan for nearby devices
	ble_devices_seen = BLE.scan(ble_devices, 30);
	Log.info(" - devices visible: %u", ble_devices_seen);
	
	// List nearby devices
	for (int x = 0; x < ble_devices_seen; x++) {
       	BleScanResult scanResult = ble_devices[x];
       	Log.info("     %s %idB", ble_devices[x].address.toString().c_str(), ble_devices[x].rssi);
	}
	
	// Look for the device we want to connect to.
	for (int x = 0; x < ble_devices_seen; x++) {
	    if (strncmp(ble_devices[x].address.toString(), ble_peer_address.toString(), 17) == 0) {
	        ble_peer_found_at = x;
	        Log.info("Found matching device %s at position %i", ble_devices[ble_peer_found_at].address.toString().c_str(), ble_peer_found_at);
	        
	        // Connect to this peer
	        Log.info(" - Connecting");
	        ble_peer = BLE.connect(ble_devices[ble_peer_found_at].address);
	        if (ble_peer.connected()) {
                Log.info(" - Connection successful");
                
                // Read all of the advertised characteristics
                ble_peer_all_chars = ble_peer.discoverAllCharacteristics();
                if (ble_peer_all_chars.size()) {
                  Log.info(" - Characteristics found: %u", ble_peer_all_chars.size());
                  // Read and display each characteristic
                  for (int y = 0; y < ble_peer_all_chars.size(); y++) {
                      
                      // Display header for short characteristics
                      if (ble_peer_all_chars[y].UUID().type() == BleUuidType::SHORT) {
                          bin2hex(&ble_peer_all_chars[y].UUID().rawBytes()[0], &ble_char_uuid_string[0], 2, 1);
                          Log.info("     SHORT 0x%s", ble_char_uuid_string);
                          
                      }
                      // Display header for long characteristics
                      if (ble_peer_all_chars[y].UUID().type() == BleUuidType::LONG) {
                          bin2hex(&ble_peer_all_chars[y].UUID().rawBytes()[12], &ble_char_uuid_string[0], 4, 1);
                          ble_char_uuid_string[8] = '-';
                          bin2hex(&ble_peer_all_chars[y].UUID().rawBytes()[10], &ble_char_uuid_string[9], 2, 1);
                          ble_char_uuid_string[13] = '-';
                          bin2hex(&ble_peer_all_chars[y].UUID().rawBytes()[8], &ble_char_uuid_string[14], 2, 1);
                          ble_char_uuid_string[18] = '-';
                          bin2hex(&ble_peer_all_chars[y].UUID().rawBytes()[6], &ble_char_uuid_string[19], 2, 1);
                          ble_char_uuid_string[23] = '-';
                          bin2hex(&ble_peer_all_chars[y].UUID().rawBytes()[0], &ble_char_uuid_string[24], 6, 1);
                          Log.info("     LONG  %s", ble_char_uuid_string); 
                      }
                      // Read the characteristic (only the first 20 bytes)
                      if (ble_peer.getCharacteristicByUUID(ble_char, ble_peer_all_chars[y].UUID())) {
                          ble_char.getValue(ble_char_value, 20);
                          bin2hex(ble_char_value, ble_char_value_string, 20, 0);
                          Log.info("       [ %s ]", ble_char_value_string);
                      } else {
                          Log.info("       [ Could not read ]");
                      }
                      
                  }
                }
                
                // Disconnect from the peer
                BLE.disconnect(ble_peer);
                Log.info(" - Disconnected");
	        } else {
	            Log.info(" - Could not connect to the device");
	        }
	    }
	}
	
	// Let us know if a match was not found
	if (ble_peer_found_at == -1) Log.info("No matching device was found");
	
	// Wait 60 seconds and then try again
	delay(60000);
}


// ==============================================================
// bin2hex
// ==============================================================
int bin2hex(const byte *input, char *output, int len, int reverse) {
    
    // Check if we have data to convert
	if (input == NULL || output == NULL || len == NULL) return 0;

    // Step through each byte
	for (int i = 0; i < len; i++) {
	    if (reverse == 1) {
		    output[i * 2]     = "0123456789ABCDEF"[input[len - (i + 1)] >> 4];
		    output[i * 2 + 1] = "0123456789ABCDEF"[input[len - (i + 1)] & 0x0F];
	    } else {
		    output[i * 2]     = "0123456789ABCDEF"[input[i] >> 4];
		    output[i * 2 + 1] = "0123456789ABCDEF"[input[i] & 0x0F];
	    }
	}
	output[len * 2] = '\0';

    // Return
	return 1;
}

My take on this issue is that it is related to the Bluetooth version you are running. For example, iPhone 8 and above use 5.0, can connect but don’t read characteristics. iPhone 7 and below use Bluetooth 4.2 and work OK. I am yet to confirm whether this is an issue with Apple devices or Particle devices?

what works for me . . .

  1. The code Jared has written both for the Xenon and iPhone App is perfect as it is.
  2. It does NOT work running on my iPhone X (iOS 13.3)
  3. Apps such as LightBlue, nRF Connect and Bluefruit show the service but NOT the chrarcteristics when run from my iPhone X
  4. On my iPad Pro 10.5 (iOS 13.3) Bluefruit shows both the service and characteristics
  5. Jared’s code when compiled and run on my iPad DOES WORK !!
  6. Jared’s code also runs on my iPhone 6 (iOS 12.4.1) !!

from my post here . . .