I am trying to get data from a glucose meter and I am not able to find good resources regarding the implementation on internet. Here is what I have been able to implement till now:
I am scanning the devices using BluetoothAdapter.LeScanCallback Interface:
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if ((device.getName() != null) && !bleDevices.contains(device)) {
bleDevices.add(device);
}
}
After getting the devices I am connecting to device using:
device.connectGatt(MainActivity.this, true, bleGattCallBack);
In BluetoothGattCallback class I am able to get the status connected in:
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
connectionState = STATE_CONNECTED;
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
connectionState = STATE_DISCONNECTED;
gatt.close();
}
}
After that onServicesDiscovered gets called
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
List<BluetoothGattService> gattServices = gatt.getServices();
for (BluetoothGattService gattService : gattServices) {
String serviceUUID = gattService.getUuid().toString();
if (serviceUUID.equals("00001808-0000-1000-8000-00805f9b34fb")) {
List<BluetoothGattCharacteristic> characteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
if (characteristic.getUuid().equals(UUID.fromString("00002a18-0000-1000-8000-00805f9b34fb"))) {
BluetoothGattCharacteristic charGM =
gatt.getService(UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"))
.getCharacteristic(UUID.fromString("00002a18-0000-1000-8000-00805f9b34fb"));
gatt.setCharacteristicNotification(charGM, true);
glucoseCharacteristic = characteristic;
BluetoothGattDescriptor descGM = charGM.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
descGM.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descGM);
} else if (characteristic.getUuid().equals(UUID.fromString("00002a52-0000-1000-8000-00805f9b34fb"))) {
BluetoothGattCharacteristic charRACP =
gatt.getService(UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"))
.getCharacteristic(UUID.fromString("00002a52-0000-1000-8000-00805f9b34fb"));
gatt.setCharacteristicNotification(charRACP, true);
BluetoothGattDescriptor descRACP = charRACP.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
descRACP.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descRACP);
}
}
}
} else {
}
}
After this onDescriptorWrite gets called:
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onDescriptorWrite: GATT_SUCCESS");
BluetoothGattCharacteristic writeRACPchar =
gatt.getService(UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"))
.getCharacteristic(UUID.fromString("00002a52-0000-1000-8000-00805f9b34fb"));
byte[] data = new byte[2];
data[0] = 0x01; // Report Stored records
data[1] = 0x01; // All records
writeRACPchar.setValue(data);
gatt.writeCharacteristic(writeRACPchar);
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
Log.d(TAG, "onDescriptorWrite: GATT_INSUFFICIENT_AUTHENTICATION");
}
} else {
Log.d(TAG, "onDescriptorWrite: GATT_INSUFFICIENT_AUTHENTICATION");
}
}
and then onCharacteristicWrite
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
Log.d(TAG, "onCharacteristicWrite: " + status + "\n" + characteristic.getUuid() + "\n" + stringBuilder.toString() + "\n" + characteristic.getValue().length);
}
}
Now, how do I proceed further? I know that I will get the data in onCharacteristicRead but that is never called.
Related
I am trying to receive notifications in a characteristic and then write text in another characteristic of the same BLE device. But when writing to the device most of the time it disconnects me, because something will not go well I imagine. This is the code.
BluetoothGatt gatt = null;
BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
gatt.close();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
BluetoothGattCharacteristic characteristic = null;
if (BLOODGLUCOSE_MODEL.equals(GlobalNames.ADF_B27)) {
characteristic = gatt.getService(BLOODGLUCOSE_SERVICEUDID).getCharacteristic(BLOODGLUCOSE_NOTIFY_CHARACTERISTICSUDID);
gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
BluetoothGattCharacteristic characteristic = null;
try {
if (BLOODGLUCOSE_MODEL.equals(GlobalNames.ADF_B27)) {
characteristic =
gatt.getService(BLOODGLUCOSE_SERVICEUDID)
.getCharacteristic(BLOODGLUCOSE_WRITE_CHARACTERISTICSUDID);
byte[] byteValue = new byte[10];
byteValue[0] = (byte)0x5A;
byteValue[1] = (byte)0x0A;
byteValue[2] = (byte)0x00;
byteValue[3] = (byte)0x14;
byteValue[4] = (byte)0x09;
byteValue[5] = (byte)0x14;
byteValue[6] = (byte)0x0A;
byteValue[7] = (byte)0x05;
byteValue[8] = (byte)0x09;
byteValue[9] = (byte)0xAF;
characteristic.setValue(byteValue);
(gatt.writeCharacteristic(characteristic);
}
} catch (NullPointerException e) { }
}
}
I can see that writeDescriptor() and writeCharacteristic always returns true.
Does anyone see any errors?
Thanks.
android 10 for BLE Bluetooth connection is not connected , i will set all permission also but i get connection status 133 issues ,how to solve this issues ,here i declare the scanning and callback code ,please check and give your idea
but below android 10 version is working fine,only issues on android 10 device ,give an idea to solve the issues
private void scanLeDevice(final boolean enable) {
if (scanner == null) {
scanner = btAdapter.getBluetoothLeScanner();
}
if (scanCallback == null) setScanCallback(null);
scanner.startScan(createScanFilters(),createScanSettings(),scanCallback);
isScanning = true;
}
ScanCallback scanCallback = new ScanCallback() {
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onScanResult(int callbackType, #NonNull ScanResult scanResult) {
if (connectedDevices.containsKey(scanResult.getDevice().getAddress())) {
return;
}
if (connectingDevices.contains(scanResult.getDevice().getAddress())) {
// If we're already connected, forget it
//Timber.d("Denied connection. Already connecting to " + scanResult.getDevice().getAddress());
return;
}
if (connectionGovernor != null && !connectionGovernor.shouldConnectToAddress(scanResult.getDevice().getAddress())) {
// If the BLEConnectionGovernor says we should not bother connecting to this peer, don't
return;
}
final BluetoothDevice device = btAdapter.getRemoteDevice(scanResult.getDevice().getAddress());
if (device == null) {
Log.e(TAG, "Device not found. Unable to connect.");
}
connectingDevices.add(scanResult.getDevice().getAddress());
// connectToDevice(device);
Timber.d("Initiating connection to " + scanResult.getDevice().getAddress());
device.connectGatt(context, false, mGattCallback, BluetoothDevice.TRANSPORT_LE );
}
#Override
public void onScanFailed(int i) {
Timber.e("Scan failed with code " + i);
}
};
#NonNull
BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(#NonNull BluetoothGatt gatt, int status, int newState) {
synchronized (connectedDevices) {
// It appears that certain events (like disconnection) won't have a GATT_SUCCESS status
// even when they proceed as expected, at least with the Motorola bluetooth stack
if (status != BluetoothGatt.GATT_SUCCESS)
Timber.w("onConnectionStateChange with newState %d and non-success status %s", newState, gatt.getDevice().getAddress());
Set<BluetoothGattCharacteristic> characteristicSet;
switch (newState) {
case BluetoothProfile.STATE_DISCONNECTING:
Timber.d("Disconnecting from " + gatt.getDevice().getAddress());
characteristicSet = discoveredCharacteristics.get(gatt.getDevice().getAddress());
for (BluetoothGattCharacteristic characteristic : characteristicSet) {
if (notifyUUIDs.contains(characteristic.getUuid())) {
Timber.d("Attempting to unsubscribe on disconneting");
setIndictaionSubscription(gatt, characteristic, false);
}
}
discoveredCharacteristics.remove(gatt.getDevice().getAddress());
break;
case BluetoothProfile.STATE_DISCONNECTED:
Timber.d("Disconnected from " + gatt.getDevice().getAddress());
connectedDevices.remove(gatt.getDevice().getAddress());
connectingDevices.remove(gatt.getDevice().getAddress());
if (transportCallback != null)
transportCallback.identifierUpdated(BLETransportCallback.DeviceType.CENTRAL,
gatt.getDevice().getAddress(),
Transport.ConnectionStatus.DISCONNECTED,
null);
characteristicSet = discoveredCharacteristics.get(gatt.getDevice().getAddress());
if (characteristicSet != null) { // Have we handled unsubscription on DISCONNECTING?
for (BluetoothGattCharacteristic characteristic : characteristicSet) {
if (notifyUUIDs.contains(characteristic.getUuid())) {
Timber.d("Attempting to unsubscribe before disconnet");
setIndictaionSubscription(gatt, characteristic, false);
}
}
} else
if ( status != BluetoothGatt.GATT_SUCCESS ) {
if ( status == 133) {
refreshDeviceCache(gatt);
}
}
gatt.close(); discoveredCharacteristics.remove(gatt.getDevice().getAddress());
break;
case BluetoothProfile.STATE_CONNECTED:
boolean mtuSuccess = gatt.requestMtu(BLETransport.DEFAULT_MTU_BYTES);
Timber.d("Connected to %s. Requested MTU success %b", gatt.getDevice().getAddress(),
mtuSuccess);
break;
}
super.onConnectionStateChange(gatt, status, newState);
}
}
#Override
public void onMtuChanged(#NonNull BluetoothGatt gatt, int mtu, int status) {
Timber.d("Got MTU (%d bytes) for device %s. Was changed successfully: %b",
mtu,
gatt.getDevice().getAddress(),
status == BluetoothGatt.GATT_SUCCESS);
mtus.put(gatt.getDevice().getAddress(), mtu);
// TODO: Can we craft characteristics and avoid discovery step?
boolean discovering = gatt.discoverServices();
Timber.d("Discovering services : " + discovering);
}
#Override
public void onServicesDiscovered(#NonNull BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS)
Timber.d("Discovered services");
else
Timber.d("Discovered services appears unsuccessful with code " + status);
// TODO: Keep this here to examine characteristics
// eventually we should get rid of the discoverServices step
boolean foundService = false;
try {
List<BluetoothGattService> serviceList = gatt.getServices();
for (BluetoothGattService service : serviceList) {
if (service.getUuid().equals(serviceUUID)) {
Timber.d("Discovered Service");
foundService = true;
HashSet<BluetoothGattCharacteristic> characteristicSet = new HashSet<>();
characteristicSet.addAll(service.getCharacteristics());
discoveredCharacteristics.put(gatt.getDevice().getAddress(), characteristicSet);
for (BluetoothGattCharacteristic characteristic : characteristicSet) {
if (notifyUUIDs.contains(characteristic.getUuid())) {
setIndictaionSubscription(gatt, characteristic, true);
}
}
}
}
if (foundService) {
synchronized (connectedDevices) {
connectedDevices.put(gatt.getDevice().getAddress(), gatt);
}
connectingDevices.remove(gatt.getDevice().getAddress());
}
} catch (Exception e) {
Timber.d("Exception analyzing discovered services " + e.getLocalizedMessage());
e.printStackTrace();
}
if (!foundService)
Timber.d("Could not discover chat service!");
super.onServicesDiscovered(gatt, status);
}
/**
* Subscribe or Unsubscribe to/from indication of a peripheral's characteristic.
*
* After calling this method you must await the result via
* {#link #onDescriptorWrite(BluetoothGatt, BluetoothGattDescriptor, int)}
* before performing any other peripheral actions.
*/
private void setIndictaionSubscription(#NonNull BluetoothGatt peripheral,
#NonNull BluetoothGattCharacteristic characteristic,
boolean enable) {
boolean success = peripheral.setCharacteristicNotification(characteristic, enable);
Timber.d("Request notification %s %s with sucess %b", enable ? "set" : "unset", characteristic.getUuid().toString(), success);
BluetoothGattDescriptor desc = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG);
desc.setValue(enable ? BluetoothGattDescriptor.ENABLE_INDICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
boolean desSuccess = peripheral.writeDescriptor(desc);
Timber.d("Wrote descriptor with success %b", desSuccess);
}
#Override
public void onDescriptorWrite(#NonNull BluetoothGatt gatt, #NonNull BluetoothGattDescriptor descriptor,
int status) {
Timber.d("onDescriptorWrite");
if (status == BluetoothGatt.GATT_SUCCESS && transportCallback != null) {
if (Arrays.equals(descriptor.getValue(), BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
transportCallback.identifierUpdated(BLETransportCallback.DeviceType.CENTRAL,
gatt.getDevice().getAddress(),
Transport.ConnectionStatus.CONNECTED,
null);
} else if (Arrays.equals(descriptor.getValue(), BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)) {
Timber.d("disabled indications successfully. Closing gatt");
gatt.close();
}
}
}
#Override
public void onCharacteristicChanged(#NonNull BluetoothGatt gatt, #NonNull BluetoothGattCharacteristic characteristic) {
Timber.d("onCharacteristicChanged %s with %d bytes", characteristic.getUuid().toString().substring(0,5),
characteristic.getValue().length);
if (transportCallback != null)
transportCallback.dataReceivedFromIdentifier(BLETransportCallback.DeviceType.CENTRAL,
characteristic.getValue(),
gatt.getDevice().getAddress());
super.onCharacteristicChanged(gatt, characteristic);
}
#Override
public void onCharacteristicWrite(#NonNull BluetoothGatt gatt,
#NonNull BluetoothGattCharacteristic characteristic, int status) {
Timber.d("onCharacteristicWrite with %d bytes", characteristic.getValue().length);
Exception exception = null;
if (status != BluetoothGatt.GATT_SUCCESS) {
String msg = "Write was not successful with code " + status;
Timber.w(msg);
exception = new UnknownServiceException(msg);
}
if (transportCallback != null)
transportCallback.dataSentToIdentifier(BLETransportCallback.DeviceType.CENTRAL,
characteristic.getValue(),
gatt.getDevice().getAddress(),
exception);
}
#Override
public void onReadRemoteRssi(#NonNull BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
}
};
now the app is working for change the bluetooth device support type
device.connectGatt(context, false, mGattCallback, BluetoothDevice.DEVICE_TYPE_LE);
but now the app is not working on huawei device , if any have idea for the device huawei for this issue
The task is to transfer information from a chip with BLE 4.0 to an Android device at high speed (at least 24 kbps). Bluetooth specification allows it. We used two methods: write / read (we write the request into one characteristic, the answer is read from the other) and notify (the chip constantly transmitted packets with a frequency of 50 ms). In the case of write / read, the time for rewriting and reading a packet varies in the region of 100 ms. When using notify, the time was set to 50 ms, but Android was losing packets. Instead, he received the old values of the packets, or missed and read the next one twice, although the chip accurately sent notifications with new values. How can I solve or work around this problem?
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
updateConnectionState(R.string.connected);
invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
invalidateOptionsMenu();
clearUI();
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
//displayGattServices(mBluetoothLeService.getSupportedGattServices());
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
stopT =System.currentTimeMillis();
//double td=stopT-startT;
time1.add(stopT - startT);
//double td = Math;
double sum = 0;
for(int i =0;i<time1.size();i++) sum+= time1.get(i);
double td = sum/time1.size();
TextView textView3 = (TextView) findViewById(R.id.textView3);
textView3.setText(String.valueOf(td));
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
//for (int i = 0; i < BluetoothLeService.byteArray.length; i++) time.add(Double.valueOf(BluetoothLeService.byteArray[i]));
float[] floatArray = new float[BluetoothLeService.byteArray.length];
for (int i = 0; i < BluetoothLeService.byteArray.length; i++) floatArray[i] = (float)BluetoothLeService.byteArray[i];
float[] tmp = new float[time2.length + floatArray.length];
System.arraycopy(time2, 0, tmp, 0, time2.length);
System.arraycopy(floatArray, 0, tmp, time2.length, floatArray.length);
time2 = tmp;
if (cnt1 < 51) {
Matr[cnt1]=floatArray;
cnt1++;
}
if (flag == 1) {
startT = System.currentTimeMillis();
//mBluetoothLeService.readCustomCharacteristic();
mBluetoothLeService.writeCustomCharacteristic(hex);
}
if(flag_notify == 1)startT = System.currentTimeMillis();
} else if (BluetoothLeService.ACTION_CHARACTERISTIC_WRITE.equals(action)) {
mBluetoothLeService.readCustomCharacteristic();
}
}
};
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
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, String.format("Received heart rate: %d", heartRate));
intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
} else {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
byteArray =data;
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
}
}
sendBroadcast(intent);
}
BluetoothGattCallback:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
//gatt.requestMtu(512);
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_CHARACTERISTIC_WRITE, characteristic);
} else {
Log.w(TAG, "onCharacteristicWrite received: " + status);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
Upd.: Changes in Callback function.
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
StopT = System.currentTimeMillis();
if (cnt1 < kolvo) {
save[cnt1]=characteristic.getValue();
td1 [cnt1] = StopT - StartT;
StartT = System.currentTimeMillis();
cnt1++;
}
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
I'm doing a programme to read data from a sensor. I'm having problems reading the characteristic. I've done the debbug and i checked that the method onCharacteristicRead() is never called, and i don't understand why.
Anyone can help me?
Thanks in advance!!
This is the class:
private Inter inter;
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
private static final String TAG = BluetoothLeService.class.getSimpleName();
//Services
private BluetoothGattService heartService;
//Characteristics
private BluetoothGattCharacteristic heartCharact;
private BluetoothGatt bluetoothGatt;
private final BluetoothGattCallback gattCallBack = new BluetoothGattCallback() {
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.d(TAG, "Entrei no onCharacteristicRead.");
if (characteristic.getUuid().equals(DeviceConstants.HEART_RATE_MEASUREMENT)) {
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, String.format("Received heart rate: %d", heartRate));
getHeartRate(String.valueOf(heartRate));
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.d(TAG, "Entrou no Método: onServicesDiscovered");
super.onServicesDiscovered(gatt, status);
//BluetoothGattCharacteristic characteristic;
if (status == BluetoothGatt.GATT_SUCCESS) {
for (int i = 0; i != bluetoothGatt.getServices().size(); i++) {
if (bluetoothGatt.getServices().get(i).getUuid().equals(DeviceConstants.HEART_RATE_SERVICE)) {
heartService = bluetoothGatt.getServices().get(i);
}
}
for (int j = 0; j != heartService.getCharacteristics().size(); j++) {
if (heartService.getCharacteristics().get(j).getUuid().equals(DeviceConstants.HEART_RATE_MEASUREMENT)) {
Log.d(TAG, "Entrou no if 2");
heartService = bluetoothGatt.getService(DeviceConstants.HEART_RATE_SERVICE);
heartCharact = heartService.getCharacteristic(DeviceConstants.HEART_RATE_MEASUREMENT);
//heartCharact.setValue(1, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
//bluetoothGatt.writeCharacteristic(heartCharact);
//bluetoothGatt.readCharacteristic(heartCharact);
Log.d(TAG, "WOOOOOW: " + heartCharact);
}
}
}
bluetoothGatt.readCharacteristic(heartCharact);
}
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTING) {
Log.d(TAG, "Connecting to " + gatt.getDevice().getName() + ", please wait...");
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d(TAG, "Connected!!");
bluetoothGatt.discoverServices();
}
}
public void getHeartRate(String hr) {
inter.getHeartRate(hr);
}
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
if (DeviceConstants.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, String.format("Received heart rate: %d", heartRate));
intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
} else {
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
}
}
sendBroadcast(intent);
}
};
private BluetoothDevice device;
private Context context;
public BluetoothLeService(BluetoothDevice device, Context context, Inter inter) {
this.device = device;
this.context = context;
this.inter = inter;
}
public void connect() {
bluetoothGatt = device.connectGatt(context, false, gattCallBack);
Log.d(TAG, "Entrou no Método: connect");
}
public void disconnect() {
bluetoothGatt.disconnect();
}
It's because some characteristic are not readable.
Have a look at this page: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
And you'll see this Property cannot be read: "Read Excluded".
You should register, then your onCharacteristicChanged callback will be called.
Attempting to read characteristics from a GATT service, the list is incomplete compared to the list I get from an iOS device, or the manufacturer guide.
I am reading the characteristics as follows:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
mBluetoothGatt = gatt;
if (shouldStartWriting && writeCharacteristicsQueue.peek() != null) {
mBluetoothGatt.writeCharacteristic(writeCharacteristicsQueue.poll());
} else {
EventBus.getDefault().post(new BTGattStatusEvent(BTGattStatusEvent.Status.CONNECTED));
Log.i(TAG, "Attempting to start service discovery:" +
gatt.discoverServices());
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
mBluetoothGatt = null;
EventBus.getDefault().post(new BTGattDisconnectedEvent());
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
EventBus.getDefault().post(new BTGattStatusEvent(BTGattStatusEvent.Status.DISCOVERED));
if (status == BluetoothGatt.GATT_SUCCESS) {
for (BluetoothGattService service : gatt.getServices()) {
LOGD(TAG, "Found Service " + service.getUuid().toString());
discoverCharacteristics(service);
}
gatt.readCharacteristic(readCharacteristicsQueue.poll());
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
parseCharacteristic(characteristic);
LOGD(TAG, String.format("%s | %s ", characteristic.getUuid(), characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 0)));//(BluetoothGattCharacteristic.FORMAT_UINT16));
if (readCharacteristicsQueue.peek() != null) {
gatt.readCharacteristic(readCharacteristicsQueue.poll());
} else {
EventBus.getDefault().post(new BTGattStatusEvent(BTGattStatusEvent.Status.DONE_DISCOVERING));
}
}
}
and
private void discoverCharacteristics(BluetoothGattService service) {
for (BluetoothGattCharacteristic gattCharacteristic : service.getCharacteristics()) {
LOGD(TAG, "Discovered UUID: " + gattCharacteristic.getUuid());
readCharacteristicsQueue.add(gattCharacteristic);
}
}
I also attempted to get this characteristic using getCharacteristic, but I received a null.
The characteristics found are:
Discovered UUID: 0000fff1-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff2-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff3-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff4-0000-1000-8000-00805f9b34fb
Discovered UUID: 0000fff5-0000-1000-8000-00805f9b34fb
However, on iOS and according to the manufacturer, there should also be a 0000fff7.
Why isn't this characteristic being read?
UPDATE:
Nothing happened here. Not one of Android's BLE scanning apps can discover it.