I've set the notification into android, It is not calling to method onCharacteristicRead()????
It does not enter into the function. Why it is happening so??
Any help is appreciated
Request the solutions.
This is my code:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
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) {
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
gattServices = mBluetoothGatt
.getService(SampleGattAttributes.SERVICES_UUID);
if (gattServices != null) {
gattCharacteristics = gattServices
.getCharacteristic(SampleGattAttributes.CHARACTERISTIC_UUID);
System.out.println("character-->" + gattCharacteristics);
}
if (gattCharacteristics != null) {
System.out.println("Characteristic not null");
System.out.println("Characteristic Properties-->"
+ gattCharacteristics.getProperties());
mBluetoothGatt.setCharacteristicNotification(gattCharacteristics,
true);
}
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
System.out.println("in read");
if (status == BluetoothGatt.GATT_SUCCESS) {
byte[] data = characteristic.getValue();
System.out.println("reading");
System.out.println(new String(data));
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
//
System.out.println("change");
byte[] data = characteristic.getValue();
System.out.println(new String(data));
}
};
Thank you in advance!!
First of all onCharacteristicRead will fire if you have read a characteristic by:
mBluetoothGatt.readCharacteristic(characteristic);
Reading a characteristic and setting up notifications are two different things. What is the type of your characteristic you want to get data from?
Is it:
read
notify
indicate
If it is read you can read the characteristic using the mBluetoothGatt.readCharacteristic(characteristic); method but if its notify or indicate first you will have to read the characteristic's descriptor by calling:
mBluetoothGatt.readDescriptor(ccc);
Once you read it, it should return data by calling the onDescriptorRead callback.
Here you can set up (subscribe) to the charactersitic through either notification or indication by calling:
mBluetoothGatt.setCharacteristicNotification(characteristic, true)
once it returns true you will need to write to the descriptor again (the value of notification or indication)
BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(CCC);
clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
// or
//clientConfig.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(clientConfig);
Once this is done you will get notifications throuhg onCharacteristicChanged callback every time the characteristic changes.
you can read more about Bluetooth connection on Android here
and about Bluetooth Characteristics here
Related
I am currently working on a bluetooth chip and I would like to display its features.
I am trying the method getService(); but this one returned to me null
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(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.getService(UUID.fromString(SampleGattAttributes.UUID_Address)));
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
};
I would like to show in the logs the list of characteristics.
thank you in advance for your help
I am trying to implement an android app that scans for BLE devices. Because I need some sort of distance information of the beacons I want to read the RSSI continuously. Currently I am able to display the RSSI but the value does not change. The application reads the value once and does not update the value. I used the sample BLE application from gitHub as a basis.
This is my Bluetooth device:
class DeviceHolder{
BluetoothDevice device;
int rssi;
public DeviceHolder(BluetoothDevice device, int rssi){
this. device = device;
this.rssi = rssi;
}
}
The list adapter:
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private ArrayList<DeviceHolder> mLeHolders;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mLeHolders = new ArrayList<DeviceHolder>();
mInflator = DeviceScanActivity.this.getLayoutInflater();
}
public void addDevice(DeviceHolder deviceHolder) {
if(!mLeDevices.contains(deviceHolder.device)) {
mLeDevices.add(deviceHolder.device);
mLeHolders.add(deviceHolder);
}
}
and the scan callback:
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
DeviceHolder deviceHolder = new DeviceHolder(device,rssi);
runOnUiThread(new DeviceAddTask( deviceHolder ) );
}
};
class DeviceAddTask implements Runnable {
DeviceHolder deviceHolder;
public DeviceAddTask( DeviceHolder deviceHolder ) {
this.deviceHolder = deviceHolder;
}
public void run() {
mLeDeviceListAdapter.addDevice(deviceHolder);
mLeDeviceListAdapter.notifyDataSetChanged();
}
}
The Bluetooth GattCallback in the BluetoothLeService Activity looks as follows:
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;
boolean rssiStatus = mBluetoothGatt.readRemoteRssi();
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 onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
public void onReadRemoteRssi(BluetoothGatt gatt,
int rssi, int status){
super.onReadRemoteRssi(gatt, rssi, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, String.format("BluetoothGatt ReadRssi[%d]", rssi));
} else {
Log.w(TAG, "onReadRemoteRssi received: " + status);
}
broadcastUpdate(ACTION_RSSI_VALUE_READ, rssi);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action, int rssi){
Log.d(TAG, "broadcastUpdate - rssi");
final Intent intent = new Intent(action);
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_RSSI, rssi);
intent.setAction(ACTION_RSSI_VALUE_READ);
sendBroadcast(intent);
}
I looked up the internet and Stackoverflow for guidance, but the provided solutions did not work for me. I am using a Samsung Galaxy S5 with Android 6.01.
Does anyone have a hint how to display the RSSI continuously for non-connected devices (while scanning)? Any hints regarding wrong implementation are welcome too.
Thanks a lot for your help!
Sayus
PS: onReadRemoteRssi is implemented because I want to read the RSSI when the devices are conected as well. This functionality is not important at this time and is only nice to have.
Your application reads an RSSI value once and doesn't update it because when you add a new BluetoothDevice into your adapter, it checks if it already contains one.
if(!mLeDevices.contains(deviceHolder.device)) {
mLeDevices.add(deviceHolder.device);
mLeHolders.add(deviceHolder);
}
Instead, I would create a Map<BluetoothDevice,Integer> where you update the rssi value for the device: mDeviceRssi.put(device, rssi).
I have an medical device(named as SnoreCoach), I have created an android app and did Bluetooth Low Energy connectivity with this device. Everything (connecting to device, writing data to characteristics etc.) is working fine except OnCharacteristicChanged is not getting triggered.
Following is my BluetoothGattCallback:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
broadcastUpdate(ACTION_GATT_CONNECTED);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
broadcastUpdate(ACTION_GATT_DISCONNECTED);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onServicesDiscovered - success");
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onCharacteristicRead - success");
broadcastUpdate(ACTION_DATA_AVAILABLE);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onCharacteristicWrite - success");
if (writeType.equals("unPair")) {
mBluetoothGatt.close();
mBluetoothGatt = null;
currentlyConnectedPeripheral = null;
}
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
Log.d(TAG, "onCharacteristicChanged");
broadcastUpdate(ACTION_DATA_AVAILABLE);
}
#Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
super.onReliableWriteCompleted(gatt, status);
Log.d(TAG, "onReliableWriteCompleted");
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
Log.d(TAG, "onReadRemoteRssi");
}
#Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
Log.d(TAG, "onMtuChanged");
}
};
Following is the "broadcastUpdate" function called from above BluetoothGattCallback:
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
In my calling activity (SettingsActivity) I have following broadcast receiver:
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
switch (action) {
case BLEService.ACTION_GATT_CONNECTED:
displayToast("Connected");
Log.d(TAG, "Connected");
mBleService.discoverServices();
break;
case BLEService.ACTION_GATT_DISCONNECTED:
displayToast("Disconnected");
break;
case BLEService.ACTION_GATT_SERVICES_DISCOVERED:
Log.d(TAG, "Services Discovered");
displayToast("Services Discovered");
mBleService.enableNotification();
break;
case BLEService.ACTION_DATA_AVAILABLE:
displayToast("Data Received");
break;
}
}
};
And below is my "enableNotification" functions:
public void enableNotification() {
BluetoothGattService snorecoachService = mBluetoothGatt.getService(SNORECOACH_SERVICE_UUID);
if (snorecoachService == null) {
Log.d(TAG, "snorecoach Service not found!");
return;
}
BluetoothGattCharacteristic bodyMovementChar = snorecoachService.getCharacteristic(BODY_MOVEMENT_UUID);
if (bodyMovementChar == null) {
Log.d(TAG, "charateristic not found!");
return;
}
mBluetoothGatt.setCharacteristicNotification(bodyMovementChar, true);
BluetoothGattDescriptor desc = bodyMovementChar.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID);
desc.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(desc);
}
Following is the flow :
1) On connection, I send an broadcast as "connected" to mGattUpdateReceive, here I then start service discovery.
2) OnServiceDiscovery, I send an broadcast as "Services Discovered" to mGattUpdateReceive, here I call "enable notofication" function to set "setCharacteristicNotification", which writes the required descriptor too.
I have tried all possible options I found from other stackOverflow questions, But I don't know what I am doing wrong that the onCharacteristic event is not getting triggered.
I have spent more than 2 days for solving this but no luck, so any help would be greatly appreciated.
If it is notifications you want rather than indications, try to change
desc.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
to
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
On receiving services the following function tries to connect to a service
#Override
public void uiAvailableServices(BluetoothGatt gatt, BluetoothDevice device, List<BluetoothGattService> services) {
BluetoothGattCharacteristic c;
BluetoothGattDescriptor d;
c = gatt.getService(ForaBgGATTUUIDs.Service.SERVICE_SENSORS).getCharacteristic(ForaBgGATTUUIDs.Characteristic.CHARACTERISTIC_DATA);
byte[] data = new byte[]{0x26};
mBleWrapper.writeDataToCharacteristic(c, data);
mBleWrapper.setNotificationForCharacteristic(c,true);
mBleWrapper.requestCharacteristicValue(c);
}
Write Data To Characteristic
public void writeDataToCharacteristic(final BluetoothGattCharacteristic ch, final byte[] dataToWrite) {
if (mBluetoothAdapter == null || mBluetoothGatt == null || ch == null) {
return;
}
// first set it locally....
ch.setValue(dataToWrite);
// ... and then "commit" changes to the peripheral
mBluetoothGatt.writeCharacteristic(ch);
}
Enables notification for descriptor
public void setNotificationForCharacteristic(BluetoothGattCharacteristic ch, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
boolean success = mBluetoothGatt.setCharacteristicNotification(ch, enabled);
if(!success) {
Log.e("------", "Seting proper notification status for characteristic failed!");
}
// This is also sometimes required (e.g. for heart rate monitors) to enable notifications/indications
// see: https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
BluetoothGattDescriptor descriptor = ch.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if(descriptor != null) {
byte[] val = enabled ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
descriptor.setValue(val);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
Request data
public void requestCharacteristicValue(BluetoothGattCharacteristic ch) {
Log.d(TAG, "requestCharacteristicValue");
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
mBluetoothGatt.readCharacteristic(ch);
// new value available will be notified in Callback Object
}
What I expect is that it will send me the results after doing the above in a callback function but in the callback function it usually tells me that the Characteristic have been successfully written.
The data i receive with my smartphone through Bluetooth LE occurs in this method in my service class
public void onCharacteristicRead(BluetoothGattCharacteristic charac, int status)
{
UUID charUuid = charac.getUuid();
Bundle mBundle = new Bundle();
Message msg = Message.obtain(mActivityHandler, HRP_VALUE_MSG);
Log.i(TAG, "onCharacteristicRead");
if (charUuid.equals(BODY_SENSOR_LOCATION))
mBundle.putByteArray(BSL_VALUE, charac.getValue());
msg.setData(mBundle);
msg.sendToTarget();
}
The Handler in the activity class is contructed like this:
private Handler mHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case HRPService.HRP_VALUE_MSG:
Log.d(TAG, "mHandler.HRP_VALUE_MSG");
Bundle data1 = msg.getData();
final byte[] bslval = data1.getByteArray(HRPService.BSL_VALUE);
runOnUiThread(new Runnable()
{
public void run()
{
if (bslval != null)
{
try
{
Log.i(TAG, "BYTE BSL VAL =" + bslval[0]);
TextView bsltv = (TextView) findViewById(R.id.BodySensorLocation);
bsltv.setText("\t" + mContext.getString(R.string.BodySensorLocation)
+ getBodySensorLocation(bslval[0]));
}
catch (Exception e)
{
Log.e(TAG, e.toString());
}
}
}
});
default:
super.handleMessage(msg);
}
}
};
Can someone tell med the relationship between those two methods ?. I receive an array of data from the remote device, and i want the data to be shown on the Textview "bsltv". How do i do this ?.
Thanks in advance
I created a class called BLEGattCallback which receives the updates. In this class I implemented the interface which you are mentioned. To receive and display the data I just
send and Intent with the needed informations put into a Bundle. Just create a BroadcastReceiver in your Activity and register it for the Action. Read all data from the Bundle and display it by calling TextView.setText(String).
The UUIDManager is just a class I created to translate the Characteristic into a readable String.
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.d(CLASSNAME, "onCharacteristicRead for Characteristic: " + characteristic.getUuid().toString());
Log.d(CLASSNAME, "onCharacteristicRead for: " + UUIDManager.getCharacteristic(characteristic.getUuid().toString()));
Intent intent = new Intent();
intent.setAction(ACTION_READ_DATA_AVAILABLE);
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data) {
stringBuilder.append(String.format("%02X ", byteChar));
}
Bundle extras = new Bundle();
extras.putString(EXTRA_CHARACTERISTIC_UUID, characteristic.getUuid().toString());
extras.putString(EXTRA_STRING_DATA, stringBuilder.toString());
extras.putByteArray(EXTRA_RAW_DATA, characteristic.getValue());
extras.putString(EXTRA_DEVICE_ADDRESS, gatt.getDevice().getAddress());
intent.putExtras(extras);
}
m_Context.sendBroadcast(intent);
} else {
Log.e(CLASSNAME, "onCharacteristicRead was not successfull!");
}
}