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
Related
I don't know what's the problem.
I'm sorry I can't speak English. Can you help me
Fixed with ble bluetooth connection. There is no room for change anymore.
The Raspberry Pi I am currently using is the Raspberry Pi 4 Model B.
#SuppressWarnings({"MissingPermission"})
private void connectSelectedDevice(String address) {
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
}
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#SuppressLint("MissingPermission")
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectedBluetoothThread = new ConnectedBluetoothThread(gatt);
mConnectedBluetoothThread.start();
mTvBluetoothStatus.setText("Connected to device");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectedBluetoothThread.cancel();
mConnectedBluetoothThread = null;
mTvBluetoothStatus.setText("Disconnected from device");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
}
};
#SuppressLint("MissingPermission")
private BluetoothGatt connectGatt(BluetoothDevice device) {
return device.connectGatt(this, false, mGattCallback);
}
#SuppressWarnings({"MissingPermission"})
private class ConnectedBluetoothThread extends Thread {
private final BluetoothGatt mmGatt;
private BluetoothGattCharacteristic mCharacteristic;
public ConnectedBluetoothThread(BluetoothGatt gatt) {
mmGatt = gatt;
BluetoothGattService service = gatt.getService(BT_UUID);
if (service != null) {
mCharacteristic = service.getCharacteristic(BT_UUID);
if (mCharacteristic == null) {
List<BluetoothGattService> gattServices = gatt.getServices();
for (BluetoothGattService gattService : gattServices) {
if (gattService.getUuid().equals(BT_UUID)) {
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
if (gattCharacteristic.getUuid().equals(BT_UUID)) {
mCharacteristic = gattCharacteristic;
break;
}
}
}
}
}
} else {
Log.e(TAG, "service is null");
}
}
public void run() {
BluetoothGattService service = mmGatt.getService(BT_UUID);
if (service == null) {
Log.e(TAG, "service is null");
return;
}
mCharacteristic = service.getCharacteristic(BT_UUID);
if (mCharacteristic == null) {
Log.e(TAG, "mCharacteristic is null");
List<BluetoothGattService> gattServices = mmGatt.getServices();
for (BluetoothGattService gattService : gattServices) {
if (gattService.getUuid().equals(BT_UUID)) {
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
if (gattCharacteristic.getUuid().equals(BT_UUID)) {
mCharacteristic = gattCharacteristic;
break;
}
}
}
}
}
if (mCharacteristic == null) {
return;
}
mmGatt.setCharacteristicNotification(mCharacteristic, true);
BluetoothGattDescriptor descriptor = mCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mmGatt.writeDescriptor(descriptor);
}
}
Please advice on how to fix it.
from bluetooth import *
server_socket= BluetoothSocket(RFCOMM)
port = 1
server_socket.bind(("", port))
server_socket.listen(1)
client_socket, address = server_socket.accept()
print("Accepted connection from ", address)
client_socket.send("bluetooth connected!")
while True:
data = client_socket.recv(1024)
print("Received: %s" %data)
if(data=="q"):
print("Quit")
break
client_socket.close()
server_socket.close()
This is python code.
I expected that if I tried to connect to ble Bluetooth using the gatt server, it would be connected, but it did not work.
Please help me.
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 made an app that communicates with an device via BLE. I wrote everything that was required for it's communication. The device receives the sent value via characteristic.setValue() , but doesn't return feedback in the method onCharacteristicChanged as is supposed to, in despite that has the descriptor set for notification. For instance i send "GTN" and should get "GTN deviceId" (like on iOS), but it calls just onCharacteristicWrite(). Checked also what properties the characteristic does support. It supports PROPERTY_NOTIFY & PROPERTY_WRITE_NO_RESPONSE. I ran out of ideas why it doesn't want to get that callback message. Can someone check and try to tell me if I made some big mistakes while sending/subscribing ??
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_LOCATION_PERMISSION = 1;
private static final int REQUEST_ENABLE_BLUETOOTH = 2;
private static final int REQUEST_ENABLE_LOCATION = 3;
private static final int BLUETOOTH_ENABLED = -1;
private static final int LOCATION_ENABLED = -1;
private static final int MANUFACTURER_ID = xxxxx;
private static final UUID SERVICE =xxxxxxxxxxxxx;
private static final UUID CHARACTERISTIC =xxxxxxxxxxxxxxxxx;
private static final UUID DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
private final static String TAG = "BLE";
private byte[] mfrData;
private BluetoothManager bluetoothManager;
private BluetoothAdapter bluetoothAdapter;
private BluetoothGatt bluetoothGatt;
private BluetoothLeScanner bluetoothLeScanner;
private BluetoothGattService customService;
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
BluetoothGattService service = gatt.getService(SERVICE);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
enableDataNotifications(gatt, characteristic);
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.d(TAG, "onCharacteristicRead: ");
}
#Override
public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(TAG, "onCharacteristicWrite: ");
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
Log.d(TAG, "onCharacteristicChanged: ");
}
#Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
Log.d(TAG, "onDescriptorRead: ");
}
#Override
public void onDescriptorWrite(final BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.d(TAG, "onDescriptorWrite: ");
checkCharacteristicProperties(gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC));
new Thread(new Runnable() {
#Override
public void run() {
writeDataToCharCommand("GTN", gatt);
}
}).start();
}
#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: ");
}
};
private ScanCallback scanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (result.getScanRecord() != null && result.getScanRecord().getManufacturerSpecificData(MANUFACTURER_ID) != null) {
Log.d(TAG, "onScanResult: found device");
bluetoothLeScanner.stopScan(scanCallback);
boolean isBonded = result.getDevice().createBond();
if (isBonded) {
bluetoothGatt = result.getDevice().connectGatt(MainActivity.this, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE);
}
}
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
Log.d(TAG, "onBatchScanResults: ");
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.d(TAG, "onScanFailed: ");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupBluetoothData();
checkIfSupportedBluetooth();
checkLocationPermission();
}
private void checkCharacteristicProperties(BluetoothGattCharacteristic pChar) {
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_READ " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_NOTIFY " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_BROADCAST " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_BROADCAST) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_EXTENDED_PROPS " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_INDICATE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_SIGNED_WRITE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_WRITE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_WRITE_NO_RESPONSE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0));
}
private void setupBluetoothData() {
bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
}
private void checkIfSupportedBluetooth() {
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
if (bluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
}
private void checkLocationPermission() {
if (!hasGrantedLocationPermission()) {
requestLocationPermission();
} else {
checkIfBluetoothEnabled();
}
}
private boolean hasGrantedLocationPermission() {
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
return result == PackageManager.PERMISSION_GRANTED;
}
private void requestLocationPermission() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
}
private void checkIfBluetoothEnabled() {
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BLUETOOTH);
} else {
displayLocationSettingsRequest();
}
}
private void displayLocationSettingsRequest() {
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).build();
googleApiClient.connect();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(10000 / 2);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(#NonNull LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS: {
scanForDevices();
break;
}
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: {
try {
status.startResolutionForResult(MainActivity.this, REQUEST_ENABLE_LOCATION);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
break;
}
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: {
break;
}
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_ENABLE_BLUETOOTH: {
if (resultCode == BLUETOOTH_ENABLED) {
displayLocationSettingsRequest();
} else {
Toast.makeText(this, "Restart app", Toast.LENGTH_SHORT).show();
}
break;
}
case REQUEST_ENABLE_LOCATION: {
if (resultCode == LOCATION_ENABLED) {
scanForDevices();
} else {
Toast.makeText(this, "Restart app", Toast.LENGTH_SHORT).show();
}
break;
}
default: {
break;
}
}
}
private void scanForDevices() {
Log.d(TAG, "scanForDevices: ");
Toast.makeText(this, "Scanning", Toast.LENGTH_SHORT).show();
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
ScanFilter scanFilter = new ScanFilter.Builder()
.setManufacturerData(0x0361, mfrData)
.build();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(Collections.singletonList(scanFilter),
scanSettings, scanCallback);
}
private String translate(byte[] value) throws UnsupportedEncodingException {
return new String(value, StandardCharsets.UTF_8);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_LOCATION_PERMISSION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkIfBluetoothEnabled();
} else {
Toast.makeText(this, "Restart app", Toast.LENGTH_SHORT).show();
}
break;
}
default: {
break;
}
}
}
private void writeDataToCharCommand(String data, BluetoothGatt gatt) {
Log.d(TAG, "writeDataToCharCommand: ");
gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC).setValue(data);
gatt.writeCharacteristic(gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC));
}
private void enableDataNotifications(BluetoothGatt gatt, BluetoothGattCharacteristic gattCharacteristic) {
Log.d(TAG, "enableDataNotifications: ");
boolean enabled = gatt.setCharacteristicNotification(gattCharacteristic, true);
if (enabled) {
BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(DESCRIPTOR);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
}
i have notification work flawlessly with BLE.
i created this method to mark a characteristics notification enabled.
public void markCharForNotification(BluetoothGattCharacteristic readableChar) {
mBluetoothGatt.setCharacteristicNotification(readableChar, true);
List<BluetoothGattDescriptor> listDescr = readableChar.getDescriptors();
BluetoothGattDescriptor descriptor = listDescr.get(0);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
hope it helps
You might want to run the checkCharacteristicProperties on the notify characteristic also.
Anyway, the correct way to enable notifications is to check the properties first and enable notify or indicate, based on those properties:
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
int properties = characteristic.getProperties();
if (descriptor != null) {
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
}
gatt.writeDescriptor(descriptor);
Hope this helps.
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);
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