23

Im trying to get UUID of ble device. I was following android developers guide and so far I can get only device name and rssi. Im trying to get Uuid of the device that comes to scanning method that looks like this:

    public void onLeScan(final BluetoothDevice device, int rssi,byte[] scanRecord) {

        ParcelUuid[] myUUid =device.getUuids();
        for(ParcelUuid a :myUUid){
            Log.d("UUID",a.getUuid().toString());
        }
        String s = new String(scanRecord);
        int len = scanRecord.length;
        String scanRecords =new String(scanRecord) ;



        deviceMap.put(device.getName().toString(), rssi);
        Message msg = MainActivity.myHandler.obtainMessage();
        Bundle bundle = new Bundle();
        bundle.putCharSequence("dev_name", device.getName().toString());
        bundle.putCharSequence("rssi", Integer.toString(rssi));
        msg.setData(bundle);
        MainActivity.myHandler.sendMessage(msg);
   }

this returns - btif_gattc_upstreams_evt: Event 4096

Chris Stratton
  • 39,853
  • 6
  • 84
  • 117
Boris Pawlowski
  • 1,781
  • 4
  • 16
  • 22

5 Answers5

42

If you want to get UUID / any other data e.g. Manufacturer Data out of scanRec[] bytes after BLE Scan, you first need to understand the data format of those Advertisement Data packet.

Came from Bluetooth.org: Advertising or Scan Response Data format

Too much theory, want to see some code snippet? This function below would straight forward print parsed raw data bytes. Now, you need to know each type code to know what data packet refers to what information. e.g. Type : 0x09, refers to BLE Device Name, Type : 0x07, refers to UUID.

public void printScanRecord (byte[] scanRecord) {

    // Simply print all raw bytes   
    try {
        String decodedRecord = new String(scanRecord,"UTF-8");
        Log.d("DEBUG","decoded String : " + ByteArrayToString(scanRecord));
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    // Parse data bytes into individual records
    List<AdRecord> records = AdRecord.parseScanRecord(scanRecord);


    // Print individual records 
    if (records.size() == 0) {
        Log.i("DEBUG", "Scan Record Empty");
    } else {
        Log.i("DEBUG", "Scan Record: " + TextUtils.join(",", records));
    }

}


public static String ByteArrayToString(byte[] ba)
{
  StringBuilder hex = new StringBuilder(ba.length * 2);
  for (byte b : ba)
    hex.append(b + " ");

  return hex.toString();
}


public static class AdRecord {

    public AdRecord(int length, int type, byte[] data) {
        String decodedRecord = "";
        try {
            decodedRecord = new String(data,"UTF-8");

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        Log.d("DEBUG", "Length: " + length + " Type : " + type + " Data : " + ByteArrayToString(data));         
    }

    // ...

    public static List<AdRecord> parseScanRecord(byte[] scanRecord) {
        List<AdRecord> records = new ArrayList<AdRecord>();

        int index = 0;
        while (index < scanRecord.length) {
            int length = scanRecord[index++];
            //Done once we run out of records
            if (length == 0) break;

            int type = scanRecord[index];
            //Done if our record isn't a valid type
            if (type == 0) break;

            byte[] data = Arrays.copyOfRange(scanRecord, index+1, index+length);

            records.add(new AdRecord(length, type, data));
            //Advance
            index += length;
        }

        return records;
    }

    // ...
}

After this parsing, those data bytes would make more sense, and you can figure out next level of decoding.

Khulja Sim Sim
  • 3,469
  • 1
  • 29
  • 28
  • For me it returns something like `64898bd, aa0ceb2, 51e6e03, ccbf180, f6b03b9, 5c923fe`.. How to convert it to UUID ? – Mr. Blond May 24 '19 at 22:30
4

As mentioned in comments, a BLE device doesn't really have a specific UUID (but rather many for included services). However, some schemes such as iBeacon encode a unique identifier in a manufacturer-specific data record in an advertising packet.

Here's a quite inefficient but conceptually simple way to convert the entire scanRecord to a hex string representation for debug printing:

String msg = "payload = ";
for (byte b : scanRecord)
  msg += String.format("%02x ", b);

Note that this will include both the actual advertising packet and a number of meaningless trailing bytes, which should be ignored after parsing the structure (length field) contained in the advertising packet itself.

Chris Stratton
  • 39,853
  • 6
  • 84
  • 117
  • 1
    Is there a clear way to convert this string to somethin like this 4CAD1A61-A9D3-428A-2913-DD84502313FC – Boris Pawlowski Feb 25 '14 at 17:26
  • Sure, remove the space and add in a counter based rule to put in the `-` where needed, possibly switching to a index style of `for` loop At this point you are asking about basic Java programming, not BLE. – Chris Stratton Feb 25 '14 at 17:28
  • Acctualy as parcing this information I can get only device name, but not UUID. – Boris Pawlowski Feb 25 '14 at 17:50
  • Doesn't seem like you are processing the scanRecord itself, but only calling the device.getName() method. – Chris Stratton Feb 25 '14 at 18:05
  • In fact, BLE devices may advertise (tough it is not mandatory) one *primary service* UUID, either a long one (128 bit, custom service) or a short one (16 bit, standard service). This is intended so that the Central device can easily sort out the peripheral devices. – jose.angel.jimenez Feb 19 '15 at 18:16
  • Yes, but the poster said they are *not* looking for a *service* UUID. – Chris Stratton Feb 19 '15 at 19:58
2

I had this same issue while developing my ble app, but after reading documentation on the following link: https://developer.android.com/reference/android/bluetooth/le/ScanResult.html

the important classes as far as UUID (Depending on the API you are developing for) is concerned are:

AdvertiseData AdvertiseData.Builder ScanRecord ScanResult

after reading through documentation for these classes, this is the code I wrote to get UUID for any device being scanned:

//For API < 21:

private BluetoothAdapter.LeScanCallback scanCallBackLe =
        new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice device, int rssi, final byte[] scanRecord) {
                final int RSSI = rssi;
                if (RSSI >= signalThreshold){
                    scanHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            AdvertiseData data = new AdvertiseData.Builder()
                                    .addServiceUuid(ParcelUuid
                                            .fromString(UUID
                                                    .nameUUIDFromBytes(scanRecord).toString())).build();
                            scannerActivity.addDevice(device, RSSI, getUUID(data));
                        }
                    });
                }
            }
        };

//For APIs less than 21, Returns Device UUID
public String getUUID(AdvertiseData data){
    List<ParcelUuid> UUIDs = data.getServiceUuids();
    //ToastMakers.message(scannerActivity.getApplicationContext(), UUIDs.toString());
    String UUIDx = UUIDs.get(0).getUuid().toString();
    Log.e("UUID", " as list ->" + UUIDx);
    return UUIDx;
}

For API's > 21:

private ScanCallback mScanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, final ScanResult result) {
        Log.i("callbackType", String.valueOf(callbackType));
        Log.i("result", result.toString());
        final int RSSI = result.getRssi();
        if (RSSI>=signalThreshold) {
            scanHandler.post(
                    new Runnable() {
                        @Override
                        public void run() {
                            BluetoothDevice device = result.getDevice();
                            scannerActivity.addDevice(device, result.getRssi(), getUUID(result));
                        }
                    });
        }
    } ...}

//For APIs greater than 21, Returns Device UUID
public String getUUID(ScanResult result){
    String UUIDx = UUID
            .nameUUIDFromBytes(result.getScanRecord().getBytes()).toString();
    ToastMakers.message(scannerActivity.getApplicationContext(), UUIDx);
    Log.e("UUID", " as String ->>" + UUIDx);
    return UUIDx;
}

I was able to obtain a 128 bit UUID of any device using this code. :)

1

I found a java library to parse the advertising packet

https://github.com/TakahikoKawasaki/nv-bluetooth

Andrew
  • 4,696
  • 1
  • 19
  • 17
-1

You can use standard android BluetoothGattCharacteristic apis like getFloatValue(int formatType, int offset), getIntValue(int formatType, int offset), getStringValue(int offset)..refer very nice android developer site tutorial here

 if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
        int flag = characteristic.getProperties();
        int format = -1;
        if ((flag & 0x01) != 0) {
            format = BluetoothGattCharacteristic.FORMAT_UINT16;
            Log.d(TAG, "Heart rate format UINT16.");
        } else {
            format = BluetoothGattCharacteristic.FORMAT_UINT8;
            Log.d(TAG, "Heart rate format UINT8.");
        }
        final int heartRate = characteristic.getIntValue(format, 1);
        Log.d(TAG, "Received heart rate: " + heartRate);
        intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
    }
rupesh jain
  • 3,410
  • 1
  • 14
  • 22
  • 1
    The line: int flag = characteristic.getProperties(); in that sample code is expected to return the mask for supported characteristic fields. **It doesn't.** It returns characteristic properties, eg PROPERTY_NOTIFY. To get the bit mask for the HRM supported characteristic fields, the first value of the characteristic needs to be read and used. Thus replacing the line int flag = characteristic.getProperties(); with something like byte[] charValue = characteristic.getValue(); byte flag = charValue[0]; will be OK. – obdkey Feb 17 '16 at 16:41