Garmin HRM Dual, not transmitting data over BLE - android

For some reason device does not transmit data (heart rate) over BLE. It connects fine, phone app is also able to discover services and connect to service.
I started up with iOS and Health app and actually saw some data coming through, so, it worked initially. Later, created the base for the BLE connectivity on Android app, it connected just fine, discovered the correct services and connected to these. And no data. Re-checked with iOS, also silence. Assuming that it is device'd problem (faulty sensors etc), took it to the shop I purchased it from. Tested it, worked like a charm with ANT+. So, it has to be BLE issue. The code itself is pretty much sample code from Android dev guides.
{
//0x180D - heart rate service
//0x2A37 - heart rate characteristic
private static HrmHandler instance;
private static UUID UUID_HRM_SERVICE = UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb");
private static UUID UUID_HRM_CHARACTERISTIC = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb");
private static String LOG_TAG = HrmHandler.class.getSimpleName();
private BluetoothAdapter mBtAdapter;
private BluetoothDevice mBtDevice;
private String mBtDeviceAddress;
private Context mContext;
public static HrmHandler getInstance() {
if (instance == null)
instance = new HrmHandler();
return instance;
}
public void connect(Context ctx) {
mContext = ctx;
BluetoothManager bt_manager = (BluetoothManager) ctx.getSystemService(Context.BLUETOOTH_SERVICE);
mBtAdapter = bt_manager.getAdapter();
if (mBtAdapter == null || !mBtAdapter.isEnabled()) return;
mBtAdapter.startLeScan(new UUID[] {UUID_HRM_SERVICE}, this);
}
public void disconnect() {
}
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
Log.v(LOG_TAG, "Found HRM device " + device.getName());
mBtDevice = device;
mBtAdapter.stopLeScan(this);
mBtDeviceAddress = mBtDevice.getAddress();
mBtDevice.connectGatt(mContext, false,this);
}
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.v(LOG_TAG, String.format("Connection state change, new state %d", newState));
if (mBtDeviceAddress == null || !mBtDeviceAddress.equals(gatt.getDevice().getAddress()))
return; //we are not interested about that connection state
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.v(LOG_TAG, "Device connected");
gatt.discoverServices();
return;
}
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.v(LOG_TAG, "Device disconnected");
return;
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (gatt != null) {
BluetoothGattCharacteristic characteristic = null;
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService s : services) {
Log.v(LOG_TAG, String.format("Discovered %s, uuid %s", s.toString(), s.getUuid().toString()));
}
BluetoothGattService service = gatt.getService(UUID_HRM_SERVICE);
if (service != null)
characteristic = service.getCharacteristic(UUID_HRM_CHARACTERISTIC);
gatt.readCharacteristic(characteristic);
gatt.setCharacteristicNotification(characteristic, true);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (!UUID_HRM_CHARACTERISTIC.equals(characteristic.getUuid())) {
Log.v(LOG_TAG, "READ: Not interesting characteristic " + characteristic.getUuid().toString());
return;
}
int flags = characteristic.getProperties();
int format = (flags & 0x01) != 0 ? BluetoothGattCharacteristic.FORMAT_UINT16 : BluetoothGattCharacteristic.FORMAT_UINT8;
int heart_rate = characteristic.getIntValue(format, 1);
Log.v(LOG_TAG, String.format("Heart rate %d bpm", heart_rate) );
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
if (!UUID_HRM_CHARACTERISTIC.equals(characteristic.getUuid())) {
Log.v(LOG_TAG, "CHANGED: Not interesting characteristic " + characteristic.getUuid().toString());
return;
}
gatt.readCharacteristic(characteristic);
}
Can anyone help me forward, especially someone at Garmin, or is it common and known issue and I just should forget about it and try to go forward with ANT+?

Related

Accessing to Heart Service in BLE device returns null

I'm trying to read the heart rate from a BLE device (It's a smartwatch and the model is CURREN R5 Pro), but when I get the Heart Rate Service, it returns null.
This is the code:
class Constants {
final static UUID HEART_RATE_SERVICE_UUID = convertFromInteger(0x180D);
final static UUID HEART_RATE_MEASUREMENT_UUID = convertFromInteger(0x2A37);
final static UUID HEART_RATE_CONTROL_POINT_UUID = convertFromInteger(0x2A39);
final static UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = convertFromInteger(0x2902);
private static UUID convertFromInteger(int i) {
final long MSB = 0x0000000000001000L;
final long LSB = 0x800000805f9b34fbL;
long value = i & 0xFFFFFFFF;
return new UUID(MSB | (value << 32), LSB);
}
}
private final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
bluetoothGatt.discoverServices();
Log.d(TAG, "Connected");
}
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d(TAG, "Disconnected");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//getCharacteristic(HEART_RATE_MEASUREMENT_UUID) returns null
BluetoothGattCharacteristic characteristic = gatt.getService(HEART_RATE_SERVICE_UUID)
.getCharacteristic(HEART_RATE_MEASUREMENT_UUID);
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) {
BluetoothGattCharacteristic characteristic = gatt.getService(HEART_RATE_SERVICE_UUID)
.getCharacteristic(HEART_RATE_CONTROL_POINT_UUID);
characteristic.setValue(DATA_STREAMING_COMMAND);
gatt.writeCharacteristic(characteristic);
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (HEART_RATE_MEASUREMENT_UUID.equals(characteristic.getUuid())) {
Log.d(TAG, "HEART_RATE_MEASUREMENT_UUID");
//PROCESS DATA
}
if (HEART_RATE_CONTROL_POINT_UUID.equals(characteristic.getUuid())) {
Log.d(TAG, "HEART_RATE_CONTROL_POINT_UUID");
//PROCESS DATA
}
}
};
However, the only app that is able to read the heart rate from the device is Wearfit. Other applications are not able to read the heart rate from this device.
The services that I'm able to get are these:
00001800-0000-1000-8000-00805f9b34fb
00001801-0000-1000-8000-00805f9b34fb
6e400001-b5a3-f393-e0a9-e50e24dcca9e
00001530-1212-efde-1523-785feabcd123
0000fee7-0000-1000-8000-00805f9b34fb
Has anyone experienced this situation? Is there anything wrong with my code? Thanks for your help.

Writing data to Bluetooth LE characteristic in Android

Although similar questions have been asked but it's slightly different. I know how to pass data to a connected BLE device but I think I'm doing something wrong for which I need help.
The code below contains all the methods from my class that is extending BroadcastReceiver.
I scan and connect to a device specified by `PEN_ADDRESS`.
In `onServicesDiscovered` method I look for a service whose `UUID` contains `abcd`.
Then I loop through the characteristics of this services and look for three characteristics with specific strings in their `UUID`.
The third characteristic is a writable characteristic in which I'm trying to write data by calling the method `writeCharac(mGatt,writeChar1,123);`
The data `123` passed above is just a dummy data.
I debugged my code while trying writing to this characteristic but on putting breakpoints inside the writeCharac method, I found that the status value is false, indicating that the write was not successful.
Am I missing something here? Please do help!
public class BackgroundReceiverFire extends BroadcastReceiver {
Context context;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mGatt;
private BluetoothLeService mBluetoothLeService;
private boolean mScanning;
private final String TAG = "READING: ";
private BluetoothDevice mDevice;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
private final String PEN_ADDRESS = "FB:23:AF:42:5C:56";
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
public void onReceive(Context context, Intent intent) {
this.context = context;
Toast.makeText(context, "Started Scanning", LENGTH_SHORT).show();
initializeBluetooth();
startScan();
}
private void initializeBluetooth() {
mHandler = new Handler();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(this.context, "No Bluetooth", LENGTH_SHORT).show();
return;
}
}
private void startScan() {
scanLeDevice(true);
}
private void stopScan() {
scanLeDevice(false);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
//Scanning for the device
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if (device.getAddress().matches(PEN_ADDRESS)) {
connectBluetooth(device);
Toast.makeText(context, "Device Found: " + device.getAddress(), Toast.LENGTH_LONG).show();
}
}
};
private void connectBluetooth(BluetoothDevice insulinPen) {
if (mGatt == null) {
Log.d("connectToDevice", "connecting to device: " + insulinPen.toString());
mDevice = insulinPen;
mGatt = insulinPen.connectGatt(context, true, gattCallback);
scanLeDevice(false);// will stop after first device detection
}
}
private void enableBluetooth() {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
}
scanLeDevice(true);
}
private void disableBluetooth() {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i("onConnectionStateChange", "Status: " + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e("gattCallback", "STATE_DISCONNECTED");
Log.i("gattCallback", "reconnecting...");
BluetoothDevice mDevice = gatt.getDevice();
mGatt = null;
connectBluetooth(mDevice);
break;
default:
Log.e("gattCallback", "STATE_OTHER");
break;
}
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
mGatt = gatt;
List<BluetoothGattService> services = mGatt.getServices();
Log.i("onServicesDiscovered", services.toString());
Iterator<BluetoothGattService> serviceIterator = services.iterator();
while(serviceIterator.hasNext()){
BluetoothGattService bleService = serviceIterator.next();
if(bleService.getUuid().toString().contains("abcd")){
//Toast.makeText(context,"Got the service",Toast.LENGTH_SHORT);
BluetoothGattCharacteristic readChar1 = bleService.getCharacteristics().get(0);
for (BluetoothGattDescriptor descriptor : readChar1.getDescriptors()) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
mGatt.setCharacteristicNotification(readChar1, true);
}
//mGatt.readCharacteristic(readChar1);
BluetoothGattCharacteristic readChar2 = bleService.getCharacteristics().get(1);
for (BluetoothGattDescriptor descriptor : readChar2.getDescriptors()) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
mGatt.setCharacteristicNotification(readChar2, true);
}
//mGatt.readCharacteristic(readChar2);
BluetoothGattCharacteristic writeChar1 = bleService.getCharacteristics().get(2);
for (BluetoothGattDescriptor descriptor : writeChar1.getDescriptors()) {
descriptor.setValue( BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
mGatt.setCharacteristicNotification(writeChar1, true);
}
writeCharac(mGatt,writeChar1,123);
}
}
//gatt.readCharacteristic(therm_char);
}
public void writeCharac(BluetoothGatt gatt, BluetoothGattCharacteristic charac, int value ){
if (mBluetoothAdapter == null || gatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*
BluetoothGattCharacteristic charac = gattService
.getCharacteristic(uuid);
*/
if (charac == null) {
Log.e(TAG, "char not found!");
}
int unixTime = value;
String unixTimeString = Integer.toHexString(unixTime);
byte[] byteArray = hexStringToByteArray(unixTimeString);
charac.setValue(byteArray);
boolean status = mGatt.writeCharacteristic(charac);
if(status){
Toast.makeText(context,"Written Successfully",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(context,"Error writing characteristic",Toast.LENGTH_SHORT).show();
}
}
public byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for(int i = 0; i < len; i+=2){
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
}
return data;
}
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic, int status) {
Log.i("onCharacteristicRead", characteristic.toString());
String characteristicValue = characteristic.getValue().toString();
Log.d("CHARACTERISTIC VALUE: ", characteristicValue);
gatt.disconnect();
}
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic) {
String value = characteristic.getValue().toString();
Log.d(TAG,value);
}
};
Although the BLE API is asynchronous in nature, the actual signal transmission is inevitably synchronous. You have to wait for the previous connect/write/read call to callback before starting any connecting/writing/reading operation.
In your code onServicesDiscovered(BluetoothGatt gatt, int status) function, you called mGatt.writeDescriptor(descriptor) twice before trying to write the characteristic. The API will refuse to start your write request as it is being busy writing the descriptor, and return false for your mGatt.writeCharacteristic(charac) call.
So just wait for the writeDescriptor to callback before calling writeCharacteristic. This nature is not well documented but you can find some source here and here.
Thanks #reTs and #pooja for suggestions. The issue was due to these two lines
mGatt = nullconnectBluetooth(mDevice);
in STATE_DISCONNECTED. I had figured it out but don't remember the exact reason. Posting it just in case it is helpful.

Android Bluetooth LE not managing 2 simultaneous connections with RN4020

I have a problem trying to connect with 2 Bluetooth LE modules (RN4020) throught native Android Bluetooth LE API and based on the Bluetooth Gatt sample of Android developers (https://developer.android.com/samples/BluetoothLeGatt/index.html). I modified BluetoothLeService.java to hold many connections instead of only one.
This is my process:
1- Start a new service which handle connections
2- Loop to connect devices:
for(String address: addresses) {
mBluetoothLeService.connect(address)
}
3- Find characteristics I need
4- Send data:
mBluetoothLeService.writeCharacteristic(address, mCharacteristic, dataArray);
The thing is that when I send data to the first module, it receive it perfect (onCharacteristicWrite() in BluetoothGattCallback() is called), then I send data to the second module and everything OK! But when I try to send data to the first module again, it doesn't receive it (tested in the board and also onCharacteristicWrite() is not called).
I also try with Reliable Write:
btGatt.beginReliableWrite();
characteristic.setValue(bytearray);
btGatt.writeCharacteristic(characteristic);
btGatt.executeReliableWrite();
but the same problem. The callback:
onReliableWriteCompleted(BluetoothGatt gatt, int status)
Status code is 6 (BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED)
I checked connection status to both modules and there were connected every time (no disconnection problem).
Here is the modified class BluetoothLeService.java:
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
// private String mBluetoothDeviceAddress;
private Map<String,BluetoothGatt> mBluetoothGatts = new HashMap<>();
private int mConnectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
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";
public final static String EXTRA_ADDRESS =
"com.example.bluetooth.le.EXTRA_ADDRESS";
public final static UUID UUID_HEART_RATE_MEASUREMENT =
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
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;
broadcastUpdate(gatt.getDevice().getAddress(), intentAction);
Log.i(TAG, "Connected to GATT server. address: " + gatt.getDevice().getAddress());
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
gatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(gatt.getDevice().getAddress(), intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.i(TAG, "--onServicesDiscovered. status: " + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(gatt.getDevice().getAddress(), 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(gatt.getDevice().getAddress(), ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.i(TAG, "--onCharacteristicWrite: value: " + Arrays.toString(characteristic.getValue()));
}
#Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
super.onReliableWriteCompleted(gatt, status);
Log.i(TAG, "--onReliableWriteCompleted: status: " + status);
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(gatt.getDevice().getAddress(), ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(String address, final String action) {
final Intent intent = new Intent(action);
intent.putExtra(EXTRA_ADDRESS, address);
sendBroadcast(intent);
}
private void broadcastUpdate(final String address, 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();
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());
}
}
intent.putExtra(EXTRA_ADDRESS, address);
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
disconnectAll();
closeAll();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/**
* Initializes a reference to the local Bluetooth adapter.
*
* #return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* #param address The device address of the destination device.
* #return Return true if the connection is initiated successfully. The connection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
BluetoothGatt btGatt = mBluetoothGatts.get(address);
// Previously connected device. Try to reconnect.
if ( btGatt != null) {
Log.d(TAG, "---Trying to use an existing mBluetoothGatt for connection.");
if (btGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "---Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
BluetoothGatt newBtGatt = device.connectGatt(this, true, mGattCallback);
Log.d(TAG, "---Trying to create a new connection. address: " + address);
mBluetoothGatts.put(address, newBtGatt);
mConnectionState = STATE_CONNECTING;
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect(String address) {
BluetoothGatt btGatt = mBluetoothGatts.get(address);
if (mBluetoothAdapter == null || btGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
Log.i(TAG, "disconnecting gatt");
btGatt.disconnect();
}
public void disconnectAll() {
// Connecting all devices
Iterator it = mBluetoothGatts.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
String address = (String) pair.getKey();
disconnect(address);
}
}
public int getConnectionState() {
return mConnectionState;
}
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close(String address, boolean removeFromMap) {
BluetoothGatt btGatt = mBluetoothGatts.get(address);
if (btGatt == null) {
return;
}
Log.i(TAG, "closing gatt");
btGatt.close();
if (removeFromMap) {
mBluetoothGatts.remove(address);
}
}
public void closeAll() {
// Connecting all devices
Iterator it = mBluetoothGatts.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
String address = (String) pair.getKey();
close(address, false);
}
}
/**
* Request a read on a given {#code BluetoothGattCharacteristic}. The read result is reported
* asynchronously through the {#code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
* callback.
*
* #param characteristic The characteristic to read from.
*/
public void readCharacteristic(String address, BluetoothGattCharacteristic characteristic) {
BluetoothGatt btGatt = mBluetoothGatts.get(address);
if (mBluetoothAdapter == null || btGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
btGatt.readCharacteristic(characteristic);
}
public void writeCharacteristic(String address, BluetoothGattCharacteristic characteristic,
byte[] bytearray) {
BluetoothGatt btGatt = mBluetoothGatts.get(address);
if (mBluetoothAdapter == null || btGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
if (characteristic == null) {
Log.w(TAG, "Characteristic == null");
}
Log.i(TAG, "--> Writing characacteristic: " + Arrays.toString(bytearray) + ", device address: " + address);
// btGatt.beginReliableWrite();
characteristic.setValue(bytearray);
// BluetoothManager bluetoothManager =
// (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
// Log.i(TAG, "--connection state: " + bluetoothManager.getConnectionState(btGatt.getDevice(), BluetoothGatt.GATT_SERVER));
btGatt.writeCharacteristic(characteristic);
// btGatt.executeReliableWrite();
}
/**
* Enables or disables notification on a give characteristic.
*
* #param characteristic Characteristic to act on.
* #param enabled If true, enable notification. False otherwise.
*/
public void setCharacteristicNotification(String address, BluetoothGattCharacteristic characteristic,
boolean enabled) {
BluetoothGatt btGatt = mBluetoothGatts.get(address);
if (mBluetoothAdapter == null || btGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
btGatt.setCharacteristicNotification(characteristic, enabled);
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
btGatt.writeDescriptor(descriptor);
}
}
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {#code BluetoothGatt#discoverServices()} completes successfully.
*
* #return A {#code List} of supported services.
*/
public List<BluetoothGattService> getSupportedGattServices(String address) {
BluetoothGatt btGatt = mBluetoothGatts.get(address);
if (btGatt == null) return null;
return btGatt.getServices();
}
}
Any ideas or libraries to handle multiple BLE connections? Thanks!

What are the steps to get notified by Bluetooth Low Energy (BLE) device?

I am working on a Bluetooth Low Energy (BLE) app. I have a BLE device (scale) which measures weight. I am able to connect with this device. But I am not getting how to read data (weight value) from it.
I want to know if my app is connected to any BLE device, so what are the steps to get notified by device in order to get updated data.
Okay, following is the for my Activity which I am using..
public class BlogBLEActivity extends Activity implements OnItemClickListener
{
private final static String TAG = BlogBLEActivity.class.getSimpleName();
private BluetoothAdapter bluetoothAdapter;
BluetoothManager bluetoothManager;
boolean hasBleFeature = false;
TextView tvMessage;
int messageId = R.string.doesnt_support_ble;
int colorId = android.R.color.holo_red_light;
private boolean mScanning;
private Handler handler = new Handler();
private static final long SCAN_PERIOD = 10000;
private static final int REQUEST_ENABLE_BT = 1209;
ListView listView;
ArrayList<BluetoothDevice> listDevices;
BleDeviceAdapter bleDeviceAdapter;
TextView tvHumidity;
TextView tvTemperature;
TextView tvPressure;
boolean isConnected = false;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.blog_ble);
initParameters();
initViews();
scanLeDevice(true);
}
#SuppressLint("NewApi")
void initParameters()
{
hasBleFeature = getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
Log.i(TAG, "hasBleFeature : " + hasBleFeature);
if (hasBleFeature)
{
messageId = R.string.supports_ble;
colorId = android.R.color.holo_blue_light;
} else
{
messageId = R.string.doesnt_support_ble;
colorId = android.R.color.holo_red_light;
}
bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();// BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled())
{
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
listDevices = new ArrayList<BluetoothDevice>();
bleDeviceAdapter = new BleDeviceAdapter(this, listDevices);
}
void initViews()
{
tvHumidity = (TextView) findViewById(R.id.blog_ble_tv_humidity);
tvTemperature = (TextView) findViewById(R.id.blog_ble_tv_temprature);
tvPressure = (TextView) findViewById(R.id.blog_ble_tv_pressure);
tvMessage = (TextView) findViewById(R.id.blog_ble_tv_message);
tvMessage.setText(getResources().getString(messageId));
tvMessage.setTextColor(getResources().getColor(colorId));
listView = (ListView) findViewById(R.id.blog_ble_list_view);
listView.setAdapter(bleDeviceAdapter);
listView.setOnItemClickListener(this);
}
#SuppressLint("NewApi")
void scanLeDevice(final boolean enable)
{
if (enable)
{
handler.postDelayed(new Runnable()
{
#SuppressLint("NewApi")
#Override
public void run()
{
mScanning = false;
bluetoothAdapter.stopLeScan(leScanCallback);
}
}, SCAN_PERIOD);
mScanning = false;
bluetoothAdapter.startLeScan(leScanCallback);
} else
{
mScanning = false;
bluetoothAdapter.stopLeScan(leScanCallback);
}
}
#SuppressLint("NewApi")
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback()
{
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)
{
runOnUiThread(new Runnable()
{
#Override
public void run()
{
if (device != null)
{
bleDeviceAdapter.add(device);
bleDeviceAdapter.notifyDataSetChanged();
}
}
});
}
};
class BleDeviceAdapter extends ArrayAdapter<BluetoothDevice>
{
public BleDeviceAdapter(Context context, List<BluetoothDevice> objects)
{
super(context, R.layout.row_ble_device, R.id.row_ble_device_tv_name, objects);
}
#SuppressLint("NewApi")
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View row = super.getView(position, convertView, parent);
ViewHolder holder = (ViewHolder) row.getTag();
if (holder == null)
{
holder = new ViewHolder(row);
row.setTag(holder);
}
BluetoothDevice device = getDevice(position);
holder.tvName.setText("" + device.getName());
Log.i(TAG, "" + device.getName());
return row;
}
}
BluetoothDevice getDevice(int position)
{
return (BluetoothDevice) listView.getAdapter().getItem(position);
}
#SuppressLint("NewApi")
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3)
{
BluetoothDevice device = getDevice(position);
Toast.makeText(this, "" + device.getName(), Toast.LENGTH_SHORT).show();
BluetoothGatt connectGatt = device.connectGatt(this, false, mGattCallback);
}
/* Client Configuration Descriptor */
private static final UUID CONFIG_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
private static final UUID KITCHEN_SCALE_SERVICE = UUID.fromString("0000780a-0000-1000-8000-00805f9b34fb");
private static final UUID KITCHEN_SCALE_FEATURE_CHAR = UUID.fromString("00008aa0-0000-1000-8000-00805f9b34fb");
private static final UUID KITCHEN_SCALE_MEASUREMENT_CHAR = UUID.fromString("00008aa1-0000-1000-8000-00805f9b34fb");
private static final UUID KITCHEN_SCALE_INTERMEDIATE_CHAR = UUID.fromString("00008aa2-0000-1000-8000-00805f9b34fb");
/*
* In this callback, we've created a bit of a state machine to enforce that
* only one characteristic be read or written at a time until all of our
* sensors are enabled and we are registered to get notifications.
*/
#SuppressLint("NewApi")
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback()
{
/* State Machine Tracking */
private int mState = 0;
private void reset()
{
mState = 0;
}
private void advance()
{
mState++;
}
/*
* Send an enable command to each sensor by writing a configuration
* characteristic. This is specific to the SensorTag to keep power low
* by disabling sensors you aren't using.
*/
private void enableNextSensor(BluetoothGatt gatt)
{
BluetoothGattCharacteristic characteristic;
switch (mState)
{
case 0:
Log.i(TAG, "Enabling weight scale");
characteristic = gatt.getService(KITCHEN_SCALE_SERVICE).getCharacteristic(KITCHEN_SCALE_FEATURE_CHAR);
Log.i(TAG, "Feature Properties : "+characteristic.getProperties());
characteristic.setValue(new byte[]
{ 0x09 });
break;
default:
mHandler.sendEmptyMessage(MSG_DISMISS);
Log.i(TAG, "All Sensors Enabled");
return;
}
gatt.writeCharacteristic(characteristic);
}
/*
* Read the data characteristic's value for each sensor explicitly
*/
private void readNextSensor(BluetoothGatt gatt)
{
BluetoothGattCharacteristic characteristic;
switch (mState)
{
case 0:
Log.i(TAG, "Reading weight cal");
characteristic = gatt.getService(KITCHEN_SCALE_SERVICE).getCharacteristic(KITCHEN_SCALE_MEASUREMENT_CHAR);
break;
default:
mHandler.sendEmptyMessage(MSG_DISMISS);
Log.i(TAG, "All Sensors Enabled");
return;
}
gatt.readCharacteristic(characteristic);
}
/*
* Enable notification of changes on the data characteristic for each
* sensor by writing the ENABLE_NOTIFICATION_VALUE flag to that
* characteristic's configuration descriptor.
*/
private void setNotifyNextSensor(BluetoothGatt gatt)
{
BluetoothGattCharacteristic characteristic;
switch (mState)
{
case 0:
Log.i(TAG, "Set notify weight ");
characteristic = gatt.getService(KITCHEN_SCALE_SERVICE).getCharacteristic(KITCHEN_SCALE_MEASUREMENT_CHAR);
break;
default:
mHandler.sendEmptyMessage(MSG_DISMISS);
Log.i(TAG, "All Sensors Enabled");
return;
}
// Enable local notifications
gatt.setCharacteristicNotification(characteristic, true);
// Enabled remote notifications
BluetoothGattDescriptor desc = characteristic.getDescriptor(CONFIG_DESCRIPTOR);
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(desc);
}
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
{
Log.i(TAG, "Connection State Change: " + status + " -> " + connectionState(newState));
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED)
{
/*
* Once successfully connected, we must next discover all the
* services on the device before we can read and write their
* characteristics.
*/
gatt.discoverServices();
mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Discovering Services..."));
} else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED)
{
/*
* If at any point we disconnect, send a message to clear the
* weather values out of the UI
*/
mHandler.sendEmptyMessage(MSG_CLEAR);
} else if (status != BluetoothGatt.GATT_SUCCESS)
{
/*
* If there is a failure at any stage, simply disconnect
*/
gatt.disconnect();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status)
{
Log.i(TAG, "Services Discovered: " + status);
if (status == BluetoothGatt.GATT_SUCCESS)
{
Log.i(TAG, "No of services discovered: " + gatt.getServices().size());
mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "No of services discovered: " + gatt.getServices().size()));
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService bluetoothGattService : services)
{
UUID uuid = bluetoothGattService.getUuid();
Log.e(TAG, ""+uuid.toString());
List<BluetoothGattCharacteristic> characteristics = bluetoothGattService.getCharacteristics();
for (BluetoothGattCharacteristic bluetoothGattCharacteristic : characteristics)
{
UUID uuidC = bluetoothGattCharacteristic.getUuid();
Log.i(TAG, "Gatt Properties : "+bluetoothGattCharacteristic.getProperties());
Log.i(TAG, ""+uuidC.toString());
CharacteristicHelper helper = new CharacteristicHelper(bluetoothGattCharacteristic);
Log.i(TAG, "isRead : "+helper.isRead());
Log.i(TAG, "isWrite : "+helper.isWrite());
Log.i(TAG, "isNotify : "+helper.isNotify());
Log.i(TAG, "isWriteNoResponse : "+helper.isWriteNoResponse());
}
}
}
// mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS,
// "Enabling Sensors..."));
/*
* With services discovered, we are going to reset our state machine
* and start working through the sensors we need to enable
*/
reset();
enableNextSensor(gatt);
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
{
Log.i(TAG, "onCharacteristicRead");
// For each read, pass the data up to the UI thread to update the
// display
/**methodToUpdateUI().*/
// After reading the initial value, next we enable notifications
setNotifyNextSensor(gatt);
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
{
Log.i(TAG, "onCharacteristicWrite");
// After writing the enable flag, next we read the initial value
readNextSensor(gatt);
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
{
Log.i(TAG, "onCharacteristicChanged");
/*
* After notifications are enabled, all updates from the device on
* characteristic value changes will be posted here. Similar to
* read, we hand these up to the UI thread to update the display.
*/
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status)
{
Log.i(TAG, "onDescriptorWrite");
// Once notifications are enabled, we move to the next sensor and
// start over with enable
advance();
enableNextSensor(gatt);
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status)
{
Log.i(TAG, "Remote RSSI: " + rssi);
}
private String connectionState(int status)
{
switch (status)
{
case BluetoothProfile.STATE_CONNECTED:
return "Connected";
case BluetoothProfile.STATE_DISCONNECTED:
return "Disconnected";
case BluetoothProfile.STATE_CONNECTING:
return "Connecting";
case BluetoothProfile.STATE_DISCONNECTING:
return "Disconnecting";
default:
return String.valueOf(status);
}
}
};
/*
* We have a Handler to process event results on the main thread
*/
private static final int MSG_PROGRESS = 201;
private static final int MSG_DISMISS = 202;
private static final int MSG_CLEAR = 301;
private Handler mHandler = new Handler()
{
#SuppressLint("NewApi")
#Override
public void handleMessage(Message msg)
{
BluetoothGattCharacteristic characteristic;
switch (msg.what)
{
case MSG_PROGRESS:
tvMessage.setText((String) msg.obj);
break;
case MSG_DISMISS:
tvMessage.setText("Service Enabled");
break;
case MSG_CLEAR:
tvMessage.setText("");
break;
}
}
};
}
In my activity, first of all I am scanning all the available devices & preparing ListView. On clicking on list item I connect to that particular device. When device's status become connected then I discover services. I have UUIDs of the device's service & its characteristics. But I am not sure how to write to any particular characteristics or enable or read data from it.
Although I have tried this thing but I don't see any success.
If any one has any idea about it, so please help me.
Had a device which required me to use
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)
instead of
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
as explained in this question
Android BLE API: GATT Notification not received
Refer the source code of sample application "bluetoothlegatt" provided on developer portal.
Sample service:
http://developer.android.com/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/BluetoothLeService.html
Using service:
http://developer.android.com/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceControlActivity.html
This example contains characteristics with read and notify properties. So you definitely find your solution. Please go to section with following code:(You may figure it out)
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
you have to differentiate the value is notification or indication, and set respective value using descriptor.setValue. if you set wrongly, you will not get the value.
This one is working for me:
to notify master device that some characteristic is change, call this function on your pheripheral:
private BluetoothGattServer server;
//init....
//on BluetoothGattServerCallback...
//call this after change the characteristic
server.notifyCharacteristicChanged(device, characteristic, false);
in your master device: enable setCharacteristicNotification after discover the service:
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
services = mGatt.getServices();
for(BluetoothGattService service : services){
if( service.getUuid().equals(SERVICE_UUID)) {
characteristicData = service.getCharacteristic(CHAR_UUID);
for (BluetoothGattDescriptor descriptor : characteristicData.getDescriptors()) {
descriptor.setValue( BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
}
gatt.setCharacteristicNotification(characteristicData, true);
}
}
if (dialog.isShowing()){
mHandler.post(new Runnable() {
#Override
public void run() {
dialog.hide();
}
});
}
}
now you can check your characteristic value is change, for example onCharacteristicRead function :
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.i("onCharacteristicRead", characteristic.toString());
byte[] value=characteristic.getValue();
String v = new String(value);
Log.i("onCharacteristicRead", "Value: " + v);
}

How to get the battery level after connect to the BLE device?

I am developing an application where I have to connect to Bluetooth device on Android 4.3.
And I want to get the battery level by using Battery_Service and Battery_Level.
public class BluetoothLeService extends Service {
private static final UUID Battery_Service_UUID =
UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
private static final UUID Battery_Level_UUID =
UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb");
public void getbattery() {
BluetoothGattService batteryService = mBluetoothGatt.getService(Battery_Service_UUID);
if(batteryService == null) {
Log.d(TAG, "Battery service not found!");
return;
}
BluetoothGattCharacteristic batteryLevel = batteryService.getCharacteristic(Battery_Level_UUID);
if(batteryLevel == null) {
Log.d(TAG, "Battery level not found!");
return;
}
mBluetoothGatt.readCharacteristic(batteryLevel);
     // What should I do that I can get the battery level ??
Log.d(TAG, "Battery level " + mBluetoothGatt.readCharacteristic(batteryLevel););
}
}
But the value of mBluetoothGatt.readCharacteristic(batteryLevel); is not the battery level value
How to read the battery?
I have solved this problem.
public class BluetoothLeService extends Service {
private static final UUID Battery_Service_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
private static final UUID Battery_Level_UUID = UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb");
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if(status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
Log.v(TAG, "characteristic.getStringValue(0) = " + characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0));
intent.putExtra(DeviceControl.EXTRAS_DEVICE_BATTERY, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0));
sendBroadcast(intent);
}
public void getbattery() {
BluetoothGattService batteryService = mBluetoothGatt.getService(Battery_Service_UUID);
if(batteryService == null) {
Log.d(TAG, "Battery service not found!");
return;
}
BluetoothGattCharacteristic batteryLevel = batteryService.getCharacteristic(Battery_Level_UUID);
if(batteryLevel == null) {
Log.d(TAG, "Battery level not found!");
return;
}
mBluetoothGatt.readCharacteristic(batteryLevel);
Log.v(TAG, "batteryLevel = " + mBluetoothGatt.readCharacteristic(batteryLevel));
}
}
When you call the function getbattery() , it will call onCharacteristicRead.
and onCharacteristicRead will call broadcastUpdate and transmit the characteristic and action to it.
And the characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0) in broadcastUpdate is the battery value of the BLE device.

Categories

Resources