Get batterylevel of more than one bluetoothdevices (beacons) - android

I want to get the battery level of more than one bluetooth device in android using the gatt service.
My current code is this (I am sorry that it looks a bit chaotic):
public void readCustomCharacteristic() {
// Initializes Bluetooth adapter.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mBluetoothAdapter.getBluetoothLeScanner().startScan(new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
//Log.i("Beacons", "callbacktype: " + String.valueOf(callbackType));
Log.i("Beacons", "result: " + result.toString());
BluetoothDevice btDevice = result.getDevice();
Log.i("Beacons", "Devicescan: " + (btDevice != null));
BluetoothGatt bluetoothGatt = btDevice.connectGatt(
getApplicationContext(), false, new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
//super.onConnectionStateChange(gatt, status, newState);
Log.i("Beacons", "areServicesDiscovered: " + gatt.discoverServices());
if(gatt.discoverServices()) {
onServicesDiscovered(gatt, status);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (gatt.discoverServices()) {
//if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d("Beacons", "Number of Services: " + gatt.getServices().size());
runOnUiThread(new Runnable() {
#Override
public void run() {
BluetoothGattCharacteristic chars = gatt.getServices().get(0).getCharacteristic(Battery_Level_UUID);
Log.i("Beacons", "charsstringval: " + chars.getValue().length);
}
});
}
}
});
}
});
}
I have to scan more than one beacon, and when it is scanning a device and it only getssometimes a service.
The problem is when the code wants to read the characteristic the service handle is again null. I'm desperate and I hope you can help me.

In short, because your runnable runs on a different thread, the value of gatt.getServices() may have changed.
I would simply retrieve the updated services list, check the size, and then only make the call if there is at least one service.
if (gatt.getServices().size() > 0) {
BluetoothGattCharacteristic chars = gatt.getServices().get(0).getCharacteristic(Battery_Level_UUID);
Log.i("Beacons", "charsstringval: " + chars.getValue().length);
}

Related

android 10 is not working on BLE Bluetooth connection

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

Setting the UUID of a bluetooth beacon device does not work correctly

I pair with my device, I connect to it, using this code
//this will try to connect to our bluetooth device
public void connectGatt(Context context, BluetoothDevice btDevice) {
this.btDevice = btDevice;
mBluetoothGatt = btDevice.connectGatt(context, false, mGattCallback);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mBluetoothGatt != null) {
mBluetoothGatt.requestMtu(512);
}
}
This is my GATT Callback:
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
tryToConnect = false;
Log.i("BluetoothService", "BluetoothService onConnectionStateChange CONNECTED");
if (back != null)
back.onResponse(REMOVE_CALLBACKS);
Log.i("", "Connected to GATT server.");
boolean discover = mBluetoothGatt.discoverServices();
Log.i("", "Attempting to start service discovery:" + discover);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange STATE_DISCONNECTED");
if (tryToConnect) {
if (back != null)
back.onResponse(REMOVE_CALLBACKS);
stopMonitoringBeacons();
stopListeningForBeacons();
mBluetoothAdapter.disable();
setSleep(1500);
mBluetoothAdapter.enable();
setSleep(1500);
Log.i("BluetoothService", "BluetoothService onConnectionStateChange WILL TRY CONNECT");
if (back != null)
back.onResponse(CONNECT);
tryToConnect = false;
}
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
tryToConnect = false;
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange onServicesDiscovered GATT_SUCCESS" + status);
Log.w("", "onServicesDiscovered GATT_SUCCESS: " + status);
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("", "list size: " + listBGS.size());
if (listBGS.size() > 0) {
if (back != null)
back.onResponse(CONFIGURE);
String character = "FF05";
if (justName)
character = "FF01";
setCharacteristic(gatt, character);
} else {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange onServicesDiscovered GATT_SUCCESS but ZERO SERVICES: " + btDevice.getBondState());
if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
setSleep(500);
if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED)
mBluetoothGatt.discoverServices();
} else if (btDevice.getBondState() == BluetoothDevice.BOND_NONE) {
askPairDevice();
}
}
} else {
askPairDevice();
Log.w("BluetoothService", "BluetoothService onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic,
int status) {
handler.removeCallbacksAndMessages(null);
Log.i("BluetoothService", "BluetoothService onCharacteristicRead");
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("BluetoothService", "BluetoothService onCharacteristicRead GATT_SUCCESS");
Log.w("", "BGC onCharacteristicRead GATT_SUCCESS: " + status + " / char: " + characteristic);
if (characteristic.getUuid().toString().toUpperCase().contains("FF05")) {
final String value = toHexadecimal(characteristic.getValue());
if (newBeacon == null || newBeacon.getName() == null) {
checkIfNeedsToChangeUUID(gatt, value);
} else if (newBeacon != null && (newBeacon.getUuid() != null || justName)) {
Log.i("BluetoothService", "BluetoothService new Beacon UUID is: " + value);
newBeacon.setUuid(Identifier.parse(value).toString());
if (back != null)
back.onResponse(CHANGED);
} else {
changeUUID(gatt, characteristic, value);
}
} else if (characteristic.getUuid().toString().toUpperCase().contains("FF01")) {
changeName(gatt, characteristic);
}
} else {
Log.i("", "");
}
}
};
The part that I am interested in is here:
public void changeUUID(final BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, String value) {
int size = value.length();
RandomString gen = new RandomString(size, new SecureRandom());
String uuid = gen.nextString();
Log.i("", "BluetoothService BGC value NEW UUID: " + uuid);
boolean change = characteristic.setValue(hexStringToByteArray(uuid));
Log.i("", "BluetoothService BGC value after: " + toHexadecimal(characteristic.getValue()) + " / has changed: " + change);
boolean statusWrite = gatt.writeCharacteristic(characteristic);
Log.i("", "BluetoothService BGC value after statusWRITE: " + statusWrite);
if (statusWrite) {
newBeacon.setUuid(Identifier.parse(toHexadecimal(characteristic.getValue())).toString());
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
setCharacteristic(gatt, "FF05");
}
});
} else {
if (back != null)
back.onResponse(ERROR);
}
}
Which will call this:
try {
Log.i("BluetoothService", "BluetoothService set characteristic: " + characteristic);
BluetoothGattCharacteristic btChar = null;
for (BluetoothGattService bgs : gatt.getServices()) {
for (final BluetoothGattCharacteristic bgc : bgs.getCharacteristics()) {
if (bgc.getUuid().toString().toUpperCase().contains(characteristic)) {
btChar = bgc;
gatt.readCharacteristic(bgc);
break;
}
}
}
final BluetoothGattCharacteristic btF = btChar;
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (btF != null)
gatt.readCharacteristic(btF);
}
}, 1000);
} catch (Exception e) {
Log.i("BluetoothService", "BluetoothService set characteristic ERROR: " + e.getMessage());
setCharacteristic(gatt, characteristic);
}
}
This works, but not 100%, I could say that it works on less than 50% of the cases. and I don't understand why. Can someone help?
I mean boolean statusWrite = gatt.writeCharacteristic(characteristic); Always returns to me "TRUE" so then if in the "changeUUID function I make after that another call, to try to log it, why is it NOT changed?
Also with other apps, if I check, my UUID is not changed, which is really weird. Why get the TRUE for the write, if value is the same?
If you look at the documentation for writeCharacteristic, you'll see this:
Returns boolean true, if the write operation was initiated successfully
The emphasis above is mine. Just because you successfully initiated the write doesn't mean it compleleted successfully, and indeed, in my apps I often see that it does not.
What you need to do is implement the callback public void onCharacteristicWrite (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status), then check the status to see if it is BluetoothGatt.GATT_SUCCESS. If not, you will need to retry the write. I usually make code that retries up to 10 times, then gives up after that, triggering code that presents an error to the user.
Most other Android Bluetooth APIs work this way -- discovering services, discovering characteristics, etc. Each one of these async operations can fail, and you have to implement the callbacks to find out if they actually succeeded or not, and add a retry strategy.

Android and BLE device

I'm building an app that should to connect a BLE device and download all the information that this device has storage in your flash memory.
So I'm building this code:
This is the Timer that I use to download ALL the information every X minutes:
TimerTask timerTask = new TimerTask() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void run() {
valore = true;
int conta = 0;
while(valore){
conta++;
if (currDevice != null) {
mGatt = currDevice.connectGatt(getBaseContext(), false, gattClientCallback);
}else{
//provo a ricollegarmi al dispositivo probabile, abbia perso la connessione con esso
scanLeDevice(true);
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
This is the method that I use to connect at BLE device:
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void connectToDevice(BluetoothDevice device) {
//VERIFICO SE IL DEVICE è QUELLO CHE VOGLIO IO
if (mGatt == null && settingApp != null
&& device.getAddress().equals(settingApp.getAddressBleSX())) {
currDevice = device;
gattClientCallback = new GattClientCallback();
mGatt = currDevice.connectGatt(getBaseContext(), false, gattClientCallback);
scanLeDevice(false);// will stop after first device detection
}
}
This is the LeScanCallback():
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
Handler h = new Handler(getApplicationContext().getMainLooper());
// Although you need to pass an appropriate context
h.post(new Runnable() {
#Override
public void run() {
// Log.i("onLeScan", device.toString());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
connectToDevice(device);
}
}
});
}
};
This the last code to effectively download data from BLE device and storage it on SqlLite
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
Handler h = new Handler(getApplicationContext().getMainLooper());
// Although you need to pass an appropriate context
h.post(new Runnable() {
#Override
public void run() {
// Log.i("onLeScan", device.toString());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
connectToDevice(device);
}
}
});
}
};
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner.startScan(filters, settings, mScanCallback);
}
} else {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}
private ScanCallback mScanCallback = new ScanCallback() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void onScanResult(int callbackType, ScanResult result) {
// Log.i("callbackType", String.valueOf(callbackType));
// Log.i("result", result.toString());
BluetoothDevice btDevice = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
btDevice = result.getDevice();
}
connectToDevice(btDevice);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
// Log.i("ScanResult - Results", sr.toString());
}
}
#Override
public void onScanFailed(int errorCode) {
// Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private class GattClientCallback extends BluetoothGattCallback {
#SuppressLint("LongLogTag")
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
try{
super.onConnectionStateChange(gatt, status, newState);
Log.i("tag", "onConnectionStateChange newState: " + newState);
if (status == BluetoothGatt.GATT_FAILURE) {
Log.e("ERROR_SERVICE", "Connection Gatt failure status " + status);
disconnectGattServer();
return;
} else if (status != BluetoothGatt.GATT_SUCCESS) {
// handle anything not SUCCESS as failure
Log.e("ERROR_SERVICE", "Connection not GATT sucess status " + status);
disconnectGattServer();
return;
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
//Log.i("INFO", "Connected to device " + gatt.getDevice().getAddress());
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("INFO", "Disconnected from device");
disconnectGattServer();
}
}catch(Exception e){
Log.e("ON_CONNECTION_STATE_CHANGE", e.getMessage());
}
}
public void disconnectGattServer() {
valore = false;
if (mGatt != null) {
mGatt.disconnect();
mGatt.close();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
// Log.i("INFO", "Device service discovery unsuccessful, status " + status);
return;
}
List<BluetoothGattCharacteristic> matchingCharacteristics =
BluetoothUtils.findCharacteristics(gatt,stringSequence);
if (matchingCharacteristics.isEmpty()) {
// Log.e("ERROR_SERVICE","Unable to find characteristics.");
return;
}else{
gatt.readCharacteristic(matchingCharacteristics.get(0));
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
SensorData mSenData = new SensorData();
mSenData.setValue(characteristic.getStringValue(0));
mSenData.setIdType(++id);
mSenData.setCharacteristic(characteristic.getUuid().toString());
mSenData.setValueTimestamp(db.getDateTime());
db.insertSensorData(mSenData);
} else {
Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);
}
}
Now, if I try to start my application, I can download some data from BLE device as 35, 36 values. After that I received this message from onConnectionStateChange method
E/ERROR_SERVICE: Connection not GATT sucess status 128
So after this error, the timer stopped. After X minutes the method restart but I'm not able to download never error from BLE device.
So how can I download all data from BLE device every X minutes and until the BLE device have data storage in yuor memory ?

How to read characteristic from BLE device until it have results?

I'm building an app that should to connect with a BLE device.
This device, storage the information that retreive from its sensors in a queque.
It is possibile that at the time X, the queque of this device have 100 items value.
Now my Android application must to connect of it, and download the data of the characteristic untile the queque of devis is empty.
This is the code that I use to read one value at time. How can I change it to get all data ?
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ble);
mHandler = new Handler();
//mSensors = db.getAllSensorTypes();
//BLUETOOTH LOW ENERGY NON SUPPORTATO
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE Not Supported",
Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//VERIFICO SE IL BLUETOOTH DEL DISPOSITIVO E' ABILITATO
//OPPURE NO. SE NON è ABILITATO DEVO CHIEDERE ALL'UTENTE DI ATTIVARLO
// Ensures Bluetooth is available on the device and it is enabled. If not,
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
tvBLE = (TextView) findViewById(R.id.tvBLE);
ibDownload = (ImageButton) findViewById(R.id.ibDownload);
//ibDownload.setEnabled(false);
ibDownload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(currDevice!=null){
GattClientCallback gattClientCallback = new GattClientCallback();
mGatt = currDevice.connectGatt(getBaseContext(), false, gattClientCallback);
scanLeDevice(false);// will stop after first device detection
}
refreshListView();
}
});
// Bluetooth is supported?
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth non supportato", Toast.LENGTH_SHORT).show();
finish();
}
}
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner.startScan(filters, settings, mScanCallback);
}
} else {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.i("callbackType", String.valueOf(callbackType));
Log.i("result", result.toString());
BluetoothDevice btDevice = result.getDevice();
connectToDevice(btDevice);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
Log.i("ScanResult - Results", sr.toString());
}
}
#Override
public void onScanFailed(int errorCode) {
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i("onLeScan", device.toString());
connectToDevice(device);
}
});
}
};
public void connectToDevice(BluetoothDevice device) {
String nomeDispositivo = device.getName();
if (mGatt == null && device.getName()!= null && device.getName().equals("Diabesity care")) {
currDevice = device;
ibDownload.setEnabled(true);
ibDownload.setImageResource(R.drawable.download_ok);
//mGatt = device.connectGatt(this, false, gattCallback);
//scanLeDevice(false);// will stop after first device detection
}
}
private class GattClientCallback extends BluetoothGattCallback {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.i("tag","onConnectionStateChange newState: " + newState);
if (status == BluetoothGatt.GATT_FAILURE) {
logError("Connection Gatt failure status " + status);
disconnectGattServer();
return;
} else if (status != BluetoothGatt.GATT_SUCCESS) {
// handle anything not SUCCESS as failure
logError("Connection not GATT sucess status " + status);
disconnectGattServer();
return;
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i("INFO","Connected to device " + gatt.getDevice().getAddress());
setConnected(true);
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("INFO","Disconnected from device");
disconnectGattServer();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.i("INFO","Device service discovery unsuccessful, status " + status);
return;
}
List<BluetoothGattCharacteristic> matchingCharacteristics = BluetoothUtils.findCharacteristics(gatt);
if (matchingCharacteristics.isEmpty()) {
logError("Unable to find characteristics.");
return;
}
ReadQueue = new ArrayList<>();
for (BluetoothGattCharacteristic characterist: matchingCharacteristics) {
ReadQueue.add(characterist);
}
ReadQueueIndex = 1;
ReadCharacteristics(ReadQueueIndex);
}
private void ReadCharacteristics(int index){
mGatt.readCharacteristic(ReadQueue.get(index));
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("INFO","Characteristic read successfully");
//readCharacteristic(characteristic);
SensorData mSenData = new SensorData();
mSenData.setValue(characteristic.getStringValue(0));
//TO-DO HO COMMENTATO QUESTA RIGA DI CODICE
// mSenData.setIdType(st.getId());
mSenData.setIdType(++id);
mSenData.setCharacteristic(characteristic.getUuid().toString());
mSenData.setValueTimestamp(db.getDateTime());
//inserisco i dati nel db
db.insertSensorData(mSenData);
ReadQueue.remove(ReadQueue.get(ReadQueueIndex));
if (ReadQueue.size() >= 0) {
ReadQueueIndex--;
if (ReadQueueIndex == -1) {
Log.i("Read Queue: ", "Complete");
}
else {
ReadCharacteristics(ReadQueueIndex);
}
}
//refreshListView();
} else {
logError("Characteristic read unsuccessful, status: " + status);
// Trying to read from the Time Characteristic? It doesnt have the property or permissions
// set to allow this. Normally this would be an error and you would want to:
// disconnectGattServer();
}
}
}
}

Using BLE - Read GATT characteristics

I'm trying to read GATT characteristic values from a Bluetooth LE device (a Heart Rate bracelet). Its specs are:
Services
Characteristics
I have not yet figured out how to "read" the specifications and "translate" them into code.
I need to show on my app the heartbeats detected by the device. What is the way to read the GATT values? A code example would be much appreciated :)
Follow my actual source code.
SETUP THE BLUETOOT CONNECTION
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
private static final long SCAN_PERIOD = 10000;
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth);
mHandler = new Handler();
// BLE is supported?
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "Bluetooth Low Energy non supportato", Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Bluetooth is supported?
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth non supportato", Toast.LENGTH_SHORT).show();
finish();
}
}
#Override
protected void onResume() {
super.onResume();
// Bluetooth is enabled?
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
scanLeDevice(true);
}
#Override
protected void onPause() {
super.onPause();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
scanLeDevice(false);
}
}
DISCOVER BLE DEVICES AND CONNECT WITH HEART RATE MONITOR
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i(TAG, "Name: " + device.getName() + " (" + device.getAddress() + ")");
String deviceAddress = device.getAddress();
if (deviceAddress.equals("C0:19:37:54:9F:30")) {
connectToDevice(device);
}
}
});
}
};
public void connectToDevice(BluetoothDevice device) {
if (mBluetoothGatt == null) {
Log.i(TAG, "Attempting to connect to device " + device.getName() + " (" + device.getAddress() + ")");
mBluetoothGatt = device.connectGatt(this, true, gattCallback);
scanLeDevice(false);// will stop after first device detection
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i(TAG, "Status: " + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
Log.i(TAG, "STATE_CONNECTED");
//BluetoothDevice device = gatt.getDevice(); // Get device
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e(TAG, "STATE_DISCONNECTED");
break;
default:
Log.e(TAG, "STATE_OTHER");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
List<BluetoothGattService> services = gatt.getServices();
Log.i(TAG, "Services: " + services.toString());
BluetoothGattCharacteristic bpm = services.get(2).getCharacteristics().get(0);
gatt.readCharacteristic(services.get(0).getCharacteristics().get(0));
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
// my attempt to read and print characteristics
byte[] charValue = characteristic.getValue();
byte flag = charValue[0];
Log.i(TAG, "Characteristic: " + flag);
//gatt.disconnect();
}
};
try with this inside gattCallback:
#Override
public synchronized void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
final byte[] dataInput = characteristic.getValue();
}
EDIT
And I think you are going to receive a byte with the hear rate data, use this function to get the int value:
public int unsignedByteToInt(byte b) {
return b & 0xFF;
}
And call it inside onCharacteristicChanged():
final byte[] dataInput = characteristic.getValue();
int hearRate = unsignedByteToInt(dataInput);
EDIT 2
Create a notification listener for the heart rate:
public void setHeartRateNotification(boolean enable){
String uuidHRCharacteristic = "YOUR CHARACTERISTIC";
BluetoothGattService mBluetoothLeService = null;
BluetoothGattCharacteristic mBluetoothGattCharacteristic = null;
for (BluetoothGattService service : mBluetoothGatt.getServices()) {
if ((service == null) || (service.getUuid() == null)) {
continue;
}
if (uuidAccelService.equalsIgnoreCase(service.getUuid().toString())) {
mBluetoothLeService = service;
}
}
if(mBluetoothLeService!=null) {
mBluetoothGattCharacteristic =
mBluetoothLeService.getCharacteristic(UUID.fromString(uuidHRCharacteristic));
}
else{
Log.i("Test","mBluetoothLeService is null");
}
if(mBluetoothGattCharacteristic!=null) {
setCharacteristicNotification(mBluetoothGattCharacteristic, enable);
Log.i("Test","setCharacteristicNotification:"+true);
}
else{
Log.i("Test","mBluetoothGattCharacteristic is null");
}
}
And set it onServiceDiscover inside gattCallback:
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.i("Test", "onServicesDiscovered received: " + status);
setHeartRateNotification(true);
}

Categories

Resources