My CLIENT_CHARACTERISTIC_CONFIG is
public final static UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
I do this to change CHARACTERISTIC:
BluetoothGatt mBluetoothGatt = device.connectGatt(this.context, false, mGattCallback);
mBluetoothGatt.connect();
BluetoothGattService mCustomService = bleScanner.getBluetoothGatt().getService(UUID.fromString(bleServiceUUID));
if(mCustomService == null){
return;
}
BluetoothGattCharacteristic mCharacteristic = mCustomService.getCharacteristic(UUID.fromString(bleCharacteristicUUID));
if(mReadCharacteristic == null){
return;
}
String message = "myMessage";
mCharacteristic.setValue(message.getBytes());
if (!mBluetoothGatt.writeCharacteristic(characteristic)) {
Log.e(TAG, "Failed to write characteristic");
} else {
Log.e(TAG, "Writed characteristic " + message);
}
After that characteristic is changed on sensor, onCharacteristicWrite is called in BluetoothGattCallback
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (!mBluetoothGatt.setCharacteristicNotification(characteristic, true)) {
DLog.e(TAG, "Notification Setup failed: "+characteristic.getUuid());
}
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG);
if (descriptor!=null){
descriptor.setValue( BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor1);
}
}
}
BUT descriptor is always NULL. And onCharacteristicChanged is never called.
Why? and is my CLIENT_CHARACTERISTIC_CONFIG right?
it was because some of devices (mine is Samsung E5 Android 4.3->updated to 5.1.1) are support BLE but doesn't support BluetoothGattDescriptor 0x2902 (see link)
to see all Descriptors which are supporter in device call this:
for (BluetoothGattDescriptor descriptor:characteristic.getDescriptors()){
Log.e(TAG, "BluetoothGattDescriptor: "+descriptor.getUuid().toString());
}
[UPDATE]
Some BLE devices doesn't support Writed characteristics, such as iBeacon
Related
I am trying to subscribe to multiple characteristics within the service and obtain notifications for both of the characteristics.
Here is my version with 1 char:
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
List<BluetoothGattCharacteristic> characteristics = gatt.getServices().get(2).getCharacteristics();
BluetoothGattCharacteristic characteristic = characteristics.get(0);
gatt.setCharacteristicNotification(characteristic, true);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
BluetoothGattDescriptor descriptor = characteristic.getDescriptors().get(0);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
if (characteristic.getUuid().equals(characteristicIDs[0])) {
Log.i(TAG,"Char for Beacons");
int threshValue = characteristic.getValue()[0];
sendBeaconToCloud(threshValue);
} else if (characteristic.getUuid().equals(characteristicIDs[1])) {
Log.d(TAG,"Char for Sensors");
convertSensorValues(characteristic.getValue());
} else {
Toast.makeText(BluetoothConnActivity.this,"Unknown char", Toast.LENGTH_SHORT).show();
}
}
So then I decided to copy the block of code within onServicesDiscovered and also
characterics.get(1)
This didn't work, so I followed the method specified in here:
How to subscribe to multiple BluetoothLE Characteristics with Android
So this is the produced code:
public List<BluetoothGattCharacteristic> chars;
public BluetoothGatt myGatt;
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
chars = gatt.getServices().get(2).getCharacteristics();
this.myGatt = gatt;
subscribeToMultiple();
}
private void subscribeToMultiple() {
if (chars.size() == 0) return;
BluetoothGattCharacteristic characteristic = chars.get(0);
myGatt.setCharacteristicNotification(characteristic, true);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
BluetoothGattDescriptor descriptor = characteristic.getDescriptors().get(0);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
myGatt.writeDescriptor(descriptor);
}
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt,descriptor,status);
chars.remove(0);
subscribeToMultiple();
}
However, I just get output:
D/BluetoothGatt: setCharacteristicNotification() - uuid: 0000a001-0000-1000-8000-00805f9b34fb enable: true
D/BluetoothGatt: setCharacteristicNotification() - uuid: 0000a002-0000-1000-8000-00805f9b34fb enable: true
but onCharacteristicChanged is never called.
I would really appreciate any help.
First you can set for 0.When you receive onCharacteristicChanged for characteristics 0 then unsubscribe from it and enable for the characteristic 1.when you receive for 1 unsubscribe for 1 and re enable 0. It worked for me once.
I have a BLE device (smartwatch) in which i want to read all data from services and use in my application(Swift and Android), How can i access data from the custom services, but i cant see the UUID in the GATT services and characteristics
You can read data using this code. it's work for me.
When you Smartwatch connected then you needs to send request for service discover. So, Below callback method triggered. In this method get your service and characteristics.
#Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
Log.e(TAG, "onServicesDiscovered: ");
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "onServicesDiscovered received: " + status);
return;
}
BluetoothGattService customService = gatt.getService(CUSTOM_SERVICE_UUID);
if (customService != null) {
customNotifyCharacteristic = customService.getCharacteristic(CUSTOM_CHARACTERISTICS_NOTIFY_UUID);
customWriteCharacteristic = customService.getCharacteristic(CUSTOM_CHARACTERISTICS_WRITE_UUID);
customReadCharacteristic = customService.getCharacteristic(CUSTOM_CHARACTERISTICS_READ_UUID);
}
}
After getting all characteristics and services send read request like below.
put below line where you need to read data.
readCharacteristic(customReadCharacteristic);
below explain readCharacteristic method.
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
So, onCharacteristicRead callback triggered.
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
byte[] data = characteristic.getValue();
}
}
byte[] data = characteristic.getValue();
return your data which you want to read form device.
I am developing and application to read and write in a custom device through Bluetooth BLE. There is no problem for writing. I am able to establish a connections, discover the service and the characteristics.
Note the call to enableRXNotification
public void startReceiving() {
boolean readOk = gatt.readCharacteristic(rx);
if (!readOk) {
Log.d("ANUBEBT", "ERROR INITIATING READ CHARACTERISTIC");
}
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
// Notify connection failure if service discovery failed.
if (status == BluetoothGatt.GATT_FAILURE) {
connectFailure();
return;
}
// Save reference to each UART characteristic.
tx = gatt.getService(SERIAL_SERVICE_UUID).getCharacteristic(TX_CHAR_UUID);
rx = gatt.getService(SERIAL_SERVICE_UUID).getCharacteristic(RX_CHAR_UUID);
enableRXNotification();
// Notify of connection completion.
notifyOnConnected(context);
}
public boolean enableRXNotification() {
if (gatt == null) return false;
BluetoothGattService SerialService = gatt.getService(SERIAL_SERVICE_UUID);
if (SerialService == null) return false;
BluetoothGattCharacteristic RxChar = SerialService.getCharacteristic(RX_CHAR_UUID);
if (RxChar == null) {
Log.d("ANUBEBT", "Error getting rx characteristic");
connectFailure();
return false;
}
if (!setCharacteristicNotification(RxChar, true)) {
Log.d("ANUBEBT", "Error setting rx notification");
connectFailure();
return false;
}
return true;
}
After that, I have tried to call readCharacteristic but always returns false. I have tried several alternatives:
Press a button and call to readCharacteristic
call to readCharacteristic in the onCharacteristicWrite callback (just to make sure there is no pending operations)
Do you know what's going on here?
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d("ANUBEBT", "onCharacteristicWrite " + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
notifyOnCommunicationError(characteristic.getStringValue(0).length(), characteristic.getStringValue(0));
}
writeInProgress = false;
startReceiving();
}
I have an Android app which can connect to a BLE device (using BMD-350), receive data from it via notifications and transmit data on a characteristic. I don't know why, but after a while the BLE device disconnects on its own, reporting error code 8 in the BondStateChanged callback. I can see data coming in to the phone right up until it disconnects. The BLE device sends data to the phone around 550 bytes/sec. The phone does not send any data to the BLE device in this time. Why is it disconnecting?
*note: This code is written in C# (Xamarin), but it's basically the same as its Java counterpart.
Connection Code:
_bleGatt = device.ConnectGatt(context, false, this);
Connection Callback:
if (newState == ProfileState.Connected)
{
if (status == GattStatus.Success)
{
gatt.DiscoverServices();
}
}
Service Discovery:
public override void OnServicesDiscovered(BluetoothGatt gatt, GattStatus status)
{
base.OnServicesDiscovered(gatt, status);
BluetoothGattService mService;
try
{
mService = gatt.GetService(UART_UUID);
}
catch
{
BluetoothConnectionError("UART service not found", gatt.Device);
return;
}
_tx = mService.GetCharacteristic(TX_UUID);
_rx = mService.GetCharacteristic(RX_UUID);
if (_tx == null)
{
BluetoothConnectionError("Tx characteristic not found", gatt.Device);
return;
}
if ((_tx.Properties | GattProperty.WriteNoResponse) == 0 && (_tx.Properties | GattProperty.Write) == 0)
{
BluetoothConnectionError("Tx characteristic not not in 'write' or 'write - no response' mode", gatt.Device);
return;
}
if (_rx == null)
{
BluetoothConnectionError("Rx characteristic not found", gatt.Device);
return;
}
if ((_rx.Properties | GattProperty.Notify) == 0)
{
BluetoothConnectionError("Rx characteristic not in 'notify' mode", gatt.Device);
return;
}
BluetoothGattDescriptor mDescriptor = _rx.GetDescriptor(CLIENT_UUID);
if (mDescriptor == null)
{
BluetoothConnectionError("Could not get descriptor", gatt.Device);
return;
}
mDescriptor.SetValue(BluetoothGattDescriptor.EnableNotificationValue.ToArray());
try
{
gatt.WriteDescriptor(mDescriptor);
}
catch
{
BluetoothConnectionError("Could not write descriptor", gatt.Device);
return;
}
ConnectionStatusChanged(ProfileState.Connected, gatt.Device);
}
Enabling Receive Notifications:
_bleGatt.SetCharacteristicNotification(_rx, true);
Reading Characteristic:
public override void OnCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic)
{
base.OnCharacteristicChanged(gatt, characteristic);
PublishNewData(characteristic.GetValue());
}
UUID's/CCCD:
private readonly UUID UART_UUID = UUID.FromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
private readonly UUID RX_UUID = UUID.FromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
private readonly UUID TX_UUID = UUID.FromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
private readonly UUID CLIENT_UUID = UUID.FromString("00002902-0000-1000-8000-00805f9b34fb");
I'm writing printing data to the BluetoothGattCharacteristic of a Zebra ZD410 printer. I do this by chunking the data into 20 byte chunks and writing a chunk at a time with the following code:
mCharacteristic.setValue(bytes);
boolean status = mGatt.writeCharacteristic(mCharacteristic);
and then waiting until I receive BluetoothGattCallback.onCharacteristicWrite() before initiating the writing of the next chunk. This works fine.
If I disconnect() and close() the BluetoothGatt and later connect to the same device again with BluetoothDevice.connectGatt() and then try to write to the Characteristic after onServicesDiscovered() has been called is done and I have my Characteristic again, writing will fail. What I mean by this is that when I write to the Characteristic now, onCharacteristicWrite() will be called with a Characteristic who's getValue() returns the value of the last write on the old Gatt.
After trying to solve this for two days and reading tons of SO posts I haven't found a solution.
How can I fix this?
EDIT
Here is the code for the BluetoothGattCallback
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback()
{
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
{
FALog.i(TAG, "onConnectionStateChange Status: " + status);
switch (newState)
{
case BluetoothProfile.STATE_CONNECTED:
FALog.i(TAG, "gattCallback STATE_CONNECTED");
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
disconnectAndCloseGatt();
mCharacteristic = null;
connectionFailed();
FALog.e(TAG, "gattCallback STATE_DISCONNECTED");
break;
default:
FALog.e(TAG, "gattCallback STATE_OTHER");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status)
{
BluetoothGattService service = gatt.getService(PRINTER_SERVICE_UUID);
if (service != null)
{
BluetoothGattCharacteristic characteristic = service.getCharacteristic
(PRINTER_SERVICE_CHARACTERISTIC_UUID);
if (characteristic != null)
{
mCharacteristic = characteristic;
mInternalState = STATE_CONNECTED;
mState = State.CONNECTED;
notifyStateChanged();
print("~JA");
FALog.d(TAG, "Printer connected");
mBluetoothActivity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
mListener.onPrinterConnected();
}
});
}
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
{
FALog.d(TAG, "received onCharacteristicWrite " + new String(characteristic.getValue()) + "; success: " +
(status == BluetoothGatt.GATT_SUCCESS));
if (status == BluetoothGatt.GATT_SUCCESS)
{
handler.removeCallbacks(writeRunnable);
popQueueAndReleaseLock();
}
}
};
Try writeCharacteristic after the onDescriptorWrite() callback instead of onServicesDiscovered() callback. writeDescriptor holds the mDeviceBusy.