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.
Related
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.
I currently have a method which writes to the BLE devices to beep it. My Bluetooth Callback goes as follows :
public class ReadWriteCharacteristic extends BluetoothGattCallback {
public ReadWriteCharacteristic(Context context, String macAddress, UUID service, UUID characteristic, Object tag, Activity activity) {
mMacAddress = macAddress;
mService = service;
mCharacteristic = characteristic;
mTag = tag;
mContext = context;
this.activity =activity;
final BluetoothManager bluetoothManager =
(BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
final private static String TAG = "ReadCharacteristic";
private Object mTag;
private String mMacAddress;
private UUID mService;
private BluetoothManager mBluetoothManager = null;
private BluetoothAdapter mBtAdapter = null;
private BluetoothGatt mBluetoothGatt = null;
private String mBluetoothDeviceAddress ="";
private UUID mCharacteristic;
BluetoothDevice device;
private Activity activity;
private BluetoothAdapter mBluetoothAdapter;
private Context mContext;
ReadWriteCharacteristic rc;
private int retry = 5;
public String getMacAddress() {
return mMacAddress;
}
public UUID getService() {
return mService;
}
public UUID getCharacteristic() {
return mCharacteristic;
}
public byte[] getValue() { return mValue; }
public void onError() {
Log.w(TAG, "onError");
}
public void readCharacteristic(){
if (retry == 0)
{
onError();
return;
}
retry--;
device = mBluetoothAdapter.getRemoteDevice(getMacAddress());
mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
int connectionState = mBluetoothManager.getConnectionState(device,
BluetoothProfile.GATT);
if (device != null) {
if (connectionState == BluetoothProfile.STATE_DISCONNECTED)
{
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null
&& getMacAddress().equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.w(TAG, "Re-use GATT connection");
if (mBluetoothGatt.connect()) {
Log.w(TAG, "Already connected, discovering services");
mBluetoothGatt.discoverServices();
//return ;
} else {
Log.w(TAG, "GATT re-connect failed.");
return;
}
}
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return;
}
Log.w(TAG, "Create a new GATT connection.");
rc= ReadWriteCharacteristic.this;
Log.w(TAG, "Starting Read [" + getService() + "|" + getCharacteristic() + "]");
mBluetoothGatt = device.connectGatt(mContext, false, rc);
refreshDeviceCache(mBluetoothGatt);
mBluetoothDeviceAddress = getMacAddress();
} else {
Log.w(TAG, "Attempt to connect in state: " + connectionState);
if(mBluetoothGatt!=null)
mBluetoothGatt.close();
readCharacteristic();
}
}
}
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.w(TAG,"onConnectionStateChange [" + status + "|" + newState + "]");
if ((newState == 2)&&(status ==0)) {
gatt.discoverServices();
}
else if(status == 133 )
{
//gatt.disconnect();
gatt.close();
mBluetoothGatt = null;
try
{
Thread.sleep(2000);
}
catch(Exception e)
{
}
readCharacteristic();
}
else{
if(mBluetoothGatt!=null)
mBluetoothGatt.close();
// gatt.close();
Log.w(TAG, "[" + status + "]");
//gatt.disconnect();
try
{
Thread.sleep(2000);
}
catch(Exception e)
{
}
mBluetoothGatt = null;
readCharacteristic();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.w(TAG,"onServicesDiscovered [" + status + "]");
BluetoothGattService bgs = gatt.getService(getService());
if (bgs != null) {
BluetoothGattCharacteristic bgc = bgs.getCharacteristic(getCharacteristic());
gatt.readCharacteristic(bgc);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
Log.w(TAG,"onCharacteristicWrite [" + status + "]");
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG,"onCharacteristicWrite [" + getDataHex(characteristic.getValue()) + "]");
// gatt.disconnect();
if(mBluetoothGatt!=null)
mBluetoothGatt.close();
// gatt.close();
// mBluetoothGatt=null;
}
else if(status ==133)
{
gatt.close();
try
{
Thread.sleep(2000);
}
catch(Exception e)
{
}
readCharacteristic();
}
else{
//gatt.disconnect();
gatt.close();
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
Log.w(TAG,"onCharacteristicRead [" + status + "]");
if (status == BluetoothGatt.GATT_SUCCESS) {
mValue = characteristic.getValue();
// Perform write operations
gatt.writeCharacteristic(bgc);
}
else if(status ==133)
{
gatt.close();
try
{
Thread.sleep(2000);
}
catch(Exception e)
{
}
readCharacteristic();
}
else {
// gatt.disconnect();
gatt.close();
}
}
}
This code works perfectly on device running Kitkat and below. But on Devices running Lollipop, this code works fine for the first instance. But from the next instance, irrespective of whether I disconnect or close the connection and try again, it just does not work. It keeps giving me a status code of 257 in onConnectionStateChange method. As far as I know, The Bluetooth GATT methods are the same for both kitkat and Lollipop devices.
What surprises me is that this code works fine on Lollipop devices when i use the old BLE API i.e startLeScan ( For eg - mBluetoothAdapter.startLeScan(mLeScanCallback);). This problem only arises when I use the new BLE API i.e BluetoothLeScanner ( scanner.startScan(filters, settings, new scancallback());). The scanning rate is really slow for Lollipop devices using the old BLE API, hence I cannot use it. I just don't understand how to solve this problem.Has anyone faced the same problem and found a solution? Any help would be deeply appreciated.
Quite a few things I would change here. Create a class variable for the data you want to read from the characteristic, such as private string heartRate;
1) You don't need the readCharacteristic() method. Instead, in the onConnectionStateChange once the device has connected properly, call mBluetoothGatt.discoverServices(). Then in the onServicesDiscovered() method I would call gatt.getServices(). Then use a foreach loop and loop through the returned services and compare the UUID of the service until you find the one you care about. Then if heartRate == null, call service.getCharacteristic(HeartRateUUID) and then read the characteristic. In onCharacteristicRead() check if the UUID is equal to the heart rate characteristic. If it is, assign the value of the characteristic to the heartRate variable. If you are interested, I can type out the methods or provide pseudocode.
2) I wouldn't call gatt.connect() followed by gatt.discoverServices(). gatt.connect() will reconnect to the current device as soon as it sees an advertisement packet from the device. I would call gatt.connect() and then call gatt.discoverServices() in the onConnectedStateChange() method.
3) In the onConnectedStateChange method don't use the gatt variable. Use mBluetoothGatt instead. mBluetoothGatt.disconnect() disconnects from the currently connected device. mBluetoothGatt.close() terminates the gatt instance. You cannot call mBluetoothGatt.connect() after calling mBluetoothGatt.Close(). This might not be needed, but if the device is connected I call mBluetoothGatt.disconnect() followed by mBluetoothGatt.close().
4) You can also chain characteristic readings together. In onCharacteristicRead(), after you get the value of the heartRate, you can immediately call characteristic.getService().getCharacteristic(UUIDTemperature) and then read that characteristic. It will call the OnCharacteristicRead method again.
Let me know if you want me to clarify anything; I'm typing on the crappy Surface Pro 3 keyboard. :)
I'm working on a Android project which is to connect Nexus 7 and a bio sensor through BLE link. The problem is that, I can successfully detect and get list of services and characteristics of the sensor. When I write some data to the specific characteristic, onCharacteristicWrite is automatically called and showed me writing operation is successful. However, the sensor never receive anything from the tablet. And if I use similar app on iPhone, everything works fine. So there's no problem with the device.
Does anyone have any idea of the problem?
Here is my code for write:
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnected = true;
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) {
mConnected = false;
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//Once detected services, write to characteristic for 6 times.
int count =6;
while(count>0){
writeCharacteristic();
count--;
}
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status){
if (status == BluetoothGatt.GATT_SUCCESS){
Log.d(TAG,"Write to Characteristic Success! !");
}
}
};
public boolean writeCharacteristic(){
//check mBluetoothGatt is available
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return false;
}
BluetoothGattService Service = mBluetoothGatt.getService(UUID_MY_SERVICE);
if (Service == null) {
Log.e(TAG, "service not found!");
return false;
}
BluetoothGattCharacteristic characteristic = Service
.getCharacteristic(UUID_MY_CHARACTERISTIC);
if (characteristic == null) {
Log.e(TAG, "char not found!");
return false;
}
byte[] value = {(byte)300,(byte)100,(byte)100};
characteristic.setValue(value);
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
return status;
}
The output shows "Write to Characteristic Success! !" for six times, thus the writing operation succeeded. However, the device shows that nothing been received from tablet. I also tried to write one byte at a time, or add a timer to let the tablet write to sensor every 2 seconds. But none of them worked. Any ideas?
(Answered by question edit. Converted to a community wiki answer. See What is the appropriate action when the answer to a question is added to the question itself? )
The OP wrote:
Follow Up:
The problem solved by manually pairing the tablet with the device first in the setting instead of pairing by code.
So only using the code snippet of connecting Gatt provided by Android is not good enough to pair the device. I should add another code I found online to pair the devices if I don't want to pair them manually every time:
private void pairDevice(BluetoothDevice device) {
try {
Log.d("pairDevice()", "Start Pairing...");
Method m = device.getClass()
.getMethod("createBond", (Class[]) null);
m.invoke(device, (Object[]) null);
Log.d("pairDevice()", "Pairing finished.");
} catch (Exception e) {
Log.e("pairDevice()", e.getMessage());
}
}