Get response Bluetooth Low Energy device - android

I'm developing an Android app than can transmit commands to a 4.0 Bluetooth serial device. I am suppose to get a response from the device. I was able to connect to the device and send the command, but how can I get this response? I have tried with a BluetoothGattServerCallback but it doesn`t work. This is my code:
public class MainActivity extends Activity {
private Handler handler;
private static final long SCAN_PERIOD = 12000;
private BluetoothAdapter btAdapter;
private LinearLayout pairedDevicesList;
private LinearLayout availableDevicesList;
private ProgressBar progressBar;
private BluetoothGatt gatt;
private List<BluetoothGattService> services;
private BluetoothGattServer gattServer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pairedDevicesList = (LinearLayout) findViewById(R.id.paired_devices);
availableDevicesList = (LinearLayout) findViewById(R.id.available_devices);
progressBar = (ProgressBar) findViewById(R.id.progress);
}
#Override
public void onResume() {
handler = new Handler();
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
gattServer = bluetoothManager.openGattServer(this, new BluetoothGattServerCallback() {
#Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
Log.i(getClass().getSimpleName(), "onCharacteristicWriteRequest");
}
#Override
public void onNotificationSent(BluetoothDevice device, int status) {
super.onNotificationSent(device, status);
Log.i(getClass().getSimpleName(), "onNotificationSent");
}
});
btAdapter = bluetoothManager.getAdapter();
final BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
pairedDevicesList.removeAllViews();
final Set<BluetoothDevice> pairedDevices = btAdapter.getBondedDevices();
if (pairedDevices != null) {
for (final BluetoothDevice pairedDevice : pairedDevices) {
addListItem(pairedDevicesList, pairedDevice);
}
}
scanLeDevice(true);
super.onResume();
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
handler.postDelayed(new Runnable() {
#Override
public void run() {
btAdapter.stopLeScan(leScanCallback);
progressBar.setVisibility(View.INVISIBLE);
}
}, SCAN_PERIOD);
btAdapter.startLeScan(leScanCallback);
progressBar.setVisibility(View.VISIBLE);
Log.i(getClass().getSimpleName(), "scanning bluetooth LE devices");
} else {
progressBar.setVisibility(View.INVISIBLE);
btAdapter.stopLeScan(leScanCallback);
}
}
// Device scan callback.
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() {
addListItem(availableDevicesList, device);
}
});
}
};
#Override
public void onPause() {
scanLeDevice(false);
super.onPause();
}
private void addListItem(final LinearLayout list, final BluetoothDevice device) {
//only add devices with the right name
if (device == null ||
device.getName() == null ||
//name of prototype: RNDEF8
!device.getName().startsWith("RND")) {
return;
}
Log.i(getClass().getSimpleName(), "device: " + device.getName());
final View item = getLayoutInflater()
.inflate(R.layout.li_bluetooth_device, list, false);
((TextView)item.findViewById(android.R.id.text1)).setText(device.getName());
item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
gatt = device.connectGatt(getApplicationContext(), false, gattCallback);
}
});
list.addView(item, 0);
}
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:
Log.i("gattCallback", "STATE_CONNECTED");
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e("gattCallback", "STATE_DISCONNECTED");
break;
default:
Log.e("gattCallback", "STATE_OTHER");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
services = gatt.getServices();
Log.i("onServicesDiscovered", services.toString());
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic
ch, int status) {
Log.i(getClass().getSimpleName(), ch.getPermissions() + "");
gatt.disconnect();
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
}
};
private static final UUID Read_UUID = UUID.fromString("00035b03-58e6-07dd-021a-08123a000300");
public void sendCommand(final byte[] value) {
BluetoothGattService service = gatt.getService(Read_UUID);
gattServer.addService(service);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString("00035b03-58e6-07dd-021a-08123a000301"));
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
characteristic.setValue(value);
gatt.setCharacteristicNotification(characteristic, true);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
Log.i(getClass().getSimpleName(), "" + gatt.writeCharacteristic(characteristic));
}
public void sendSU(View view) {
Log.i(getClass().getSimpleName(), "clicked su");
sendCommand("\r".getBytes());
}
public void sendSL(View view) {
Log.i(getClass().getSimpleName(), "clicked sl");
sendCommand("SL".getBytes());
}
public void sendSP(View view) {
Log.i(getClass().getSimpleName(), "clicked sp");
sendCommand("SP".getBytes());
}
}
Thanks!

Related

Read and notify BLE android

I wrote a code in which I am able to read a notify value from a hear rate sensor when it changes.
But I need also to read the battery level of the device, which is another service from the emulated device, but whenever I try to read the battery value, the first part don't even send the notify values from the heart rate.
Here is the code:
public class MainActivity extends AppCompatActivity {
BluetoothManager btManager;
BluetoothAdapter btAdapter;
BluetoothLeScanner btScanner;
Button startScanningButton;
Button stopScanningButton;
TextView peripheralTextView;
private final static int REQUEST_ENABLE_BT = 1;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
Boolean btScanning = false;
int deviceIndex = 0;
ArrayList<BluetoothDevice> devicesDiscovered = new ArrayList<BluetoothDevice>();
EditText deviceIndexInput;
Button connectToDevice;
Button disconnectDevice;
BluetoothGatt bluetoothGatt;
UUID HEART_RATE_SERVICE_UUID = convertFromInteger(0x180D);
UUID HEART_RATE_MEASUREMENT_CHAR_UUID = convertFromInteger(0x2A37);
UUID HEART_RATE_CONTROL_POINT_CHAR_UUID = convertFromInteger(0x2A39);
UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = convertFromInteger(0x2902);
UUID BATTERY_LEVEL = convertFromInteger(0x2A19);
UUID BATTERY_SERVICE = convertFromInteger(0x180F);
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 Map<String, String> uuids = new HashMap<String, String>();
// Stops scanning after 5 seconds.
private Handler mHandler = new Handler();
private static final long SCAN_PERIOD = 1000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
peripheralTextView = (TextView) findViewById(R.id.PeripheralTextView);
peripheralTextView.setMovementMethod(new ScrollingMovementMethod());
deviceIndexInput = (EditText) findViewById(R.id.InputIndex);
deviceIndexInput.setText("0");
connectToDevice = (Button) findViewById(R.id.ConnectButton);
connectToDevice.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
connectToDeviceSelected();
}
});
disconnectDevice = (Button) findViewById(R.id.DisconnectButton);
disconnectDevice.setVisibility(View.INVISIBLE);
disconnectDevice.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
disconnectDeviceSelected();
}
});
startScanningButton = (Button) findViewById(R.id.StartScanButton);
startScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startScanning();
}
});
stopScanningButton = (Button) findViewById(R.id.StopScanButton);
stopScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
stopScanning();
}
});
stopScanningButton.setVisibility(View.INVISIBLE);
btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = btManager.getAdapter();
btScanner = btAdapter.getBluetoothLeScanner();
if (btAdapter != null && !btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
// Make sure we have access coarse location enabled, if not, prompt the user to enable it
/* if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect peripherals.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}*/
//client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
// Device scan callback.
private ScanCallback leScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
peripheralTextView.append("Index: " + deviceIndex + ", Device Name: " + result.getDevice().getName() + " rssi: " + result.getRssi() + ", MAC: " + result.getDevice().getAddress() + "\n");
devicesDiscovered.add(result.getDevice());
deviceIndex++;
// auto scroll for text view
final int scrollAmount = peripheralTextView.getLayout().getLineTop(peripheralTextView.getLineCount()) - peripheralTextView.getHeight();
// if there is no need to scroll, scrollAmount will be <=0
if (scrollAmount > 0) {
peripheralTextView.scrollTo(0, scrollAmount);
}
}
};
// Device connect call back
private final BluetoothGattCallback btleGattCallback = new BluetoothGattCallback() {
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
// this will get called anytime you perform a read or write characteristic operation
final byte[] teste = characteristic.getValue();
final String batida = teste.toString();
final String result = "result";
int format = BluetoothGattCharacteristic.FORMAT_UINT8;
final int heartRate = characteristic.getIntValue(format, 1);
String TAG = "d";
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
Log.v(result , batida);
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("value of sensor (BPM) "+ heartRate + "\n");
}
});
}
#Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
// this will get called when a device connects or disconnects
System.out.println(newState);
switch (newState) {
case 0:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("device disconnected\n");
connectToDevice.setVisibility(View.VISIBLE);
disconnectDevice.setVisibility(View.INVISIBLE);
}
});
break;
case 2:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("device connected\n");
connectToDevice.setVisibility(View.INVISIBLE);
disconnectDevice.setVisibility(View.VISIBLE);
}
});
// discover services and characteristics for this device
bluetoothGatt.discoverServices();
break;
default:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("we encounterned an unknown state, uh oh\n");
}
});
break;
}
}
#Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
// this will get called after the client initiates a BluetoothGatt.discoverServices() call
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("device services have been discovered\n");
}
});
displayGattServices(bluetoothGatt.getServices());
BluetoothGattCharacteristic characteristic = gatt.getService(HEART_RATE_SERVICE_UUID).getCharacteristic(HEART_RATE_MEASUREMENT_CHAR_UUID);
//BluetoothGattCharacteristic battery = gatt.getService(BATTERY_SERVICE).getCharacteristic(BATTERY_LEVEL);
//gatt.readCharacteristic(battery);
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_CHAR_UUID);
characteristic.setValue(new byte[]{1,1});
gatt.writeCharacteristic(characteristic);
}
#Override
// Result of a characteristic read operation
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) {
System.out.println(characteristic.getUuid());
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
System.out.println("coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
public void startScanning() {
System.out.println("start scanning");
btScanning = true;
deviceIndex = 0;
devicesDiscovered.clear();
peripheralTextView.setText("");
peripheralTextView.append("Started Scanning\n");
startScanningButton.setVisibility(View.INVISIBLE);
stopScanningButton.setVisibility(View.VISIBLE);
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.startScan(leScanCallback);
}
});
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
stopScanning();
}
}, SCAN_PERIOD);
}
public void stopScanning() {
System.out.println("stopping scanning");
peripheralTextView.append("Stopped Scanning\n");
btScanning = false;
startScanningButton.setVisibility(View.VISIBLE);
stopScanningButton.setVisibility(View.INVISIBLE);
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.stopScan(leScanCallback);
}
});
}
public void connectToDeviceSelected() {
peripheralTextView.append("Trying to connect to device at index: " + deviceIndexInput.getText() + "\n");
int deviceSelected = Integer.parseInt(deviceIndexInput.getText().toString());
bluetoothGatt = devicesDiscovered.get(deviceSelected).connectGatt(this, false, btleGattCallback);
}
public void disconnectDeviceSelected() {
peripheralTextView.append("Disconnecting from device\n");
bluetoothGatt.disconnect();
}
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null) return;
// Loops through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
final String uuid = gattService.getUuid().toString();
System.out.println("Service discovered: " + uuid);
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("Service disovered: "+uuid+"\n");
}
});
new ArrayList<HashMap<String, String>>();
List<BluetoothGattCharacteristic> gattCharacteristics =
gattService.getCharacteristics();
// Loops through available Characteristics.
for (BluetoothGattCharacteristic gattCharacteristic :
gattCharacteristics) {
final String charUuid = gattCharacteristic.getUuid().toString();
System.out.println("Characteristic discovered for service: " + charUuid);
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("Characteristic discovered for service: "+charUuid+"\n");
}
});
}
}
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onStop() {
super.onStop();
}
public UUID convertFromInteger(int i) {
final long MSB = 0x0000000000001000L;
final long LSB = 0x800000805f9b34fbL;
long value = i & 0xFFFFFFFF;
return new UUID(MSB | (value << 32), LSB);
}
}
How can I read without interrupting the notify from BLE?
As you've observed, you can't start these two operations simultaneously (the first one will be overwritten and never executes):
gatt.readCharacteristic(battery);
gatt.writeDescriptor(descriptor);
Instead, you have to do the first operation, wait for it to finish (in your example, by waiting for onCharacteristicRead to be called), and then start the second operation. A common way to implement this is to use a queue to store pending operations, then pop items off the front of the queue and execute them one at a time in the rest of your code.
This required queuing is an annoying aspect of the Android BLE APIs that is not described in the documentation. For more details, check out my talk or list of resources for Android BLE.

Android BLE get connected but do not get any callback at BluetoothGattCallback()

I have an Arduino code driven ESP32 chip.
For Android code, it setup a callback for connection attempt
mGatt = device.connectGatt(this, false, gattCallback, TRANSPORT_LE );
but
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback()
do not happen.
However, from Arduino side, it does see a connected happen and start to send data out. ESP32 also blink connected LED.
Any idea what was wrong?
SDK version is 26,
minSDK is 23,
targetSDK is 23,
run on Samsung Galaxy S7
thanks a lot!
#TargetApi(21)
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter;
private int REQUEST_ENABLE_BT = 1;
private Handler mHandler;
private static final long SCAN_PERIOD = 10000;
private BluetoothLeScanner mLEScanner;
private ScanSettings settings;
private List<ScanFilter> filters;
private BluetoothGatt mGatt;
private TextView line_1, line_2, line_3, line_4;
private ImageButton btnTrash, btnEmail;
private UUID uuid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uuid = UUID.fromString("8dc99748-0ad4-11e8-ba89-0ed5f89f718b");
line_1 = (TextView) findViewById(R.id.textLine1);
line_2 = (TextView) findViewById(R.id.textLine2);
line_3 = (TextView) findViewById(R.id.textLine3);
line_4 = (TextView) findViewById(R.id.textLine4);
mHandler = new Handler();
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE Not Supported",
Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
line_3.setText("" + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
line_1.setText(" connected ");
Toast.makeText(getApplicationContext()," connected ", Toast.LENGTH_LONG);
// gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e("gattCallback", "STATE_DISCONNECTED");
break;
default:
Log.e("gattCallback", "STATE_OTHER");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
List<BluetoothGattService> services = gatt.getServices();
line_1.setText(" server discover");
gatt.readCharacteristic(services.get(1).getCharacteristics().get
(0));
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic, int status) {
Log.i("onCharacteristicRead", characteristic.toString());
gatt.disconnect();
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic)
{
line_1.setText(" charactertics changed");
}
};
#Override
protected void onResume() {
super.onResume();
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} else {
if (Build.VERSION.SDK_INT >= 21) {
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
filters = new ArrayList<ScanFilter>();
}
scanLeDevice(true);
}
}
#Override
protected void onPause() {
super.onPause();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
scanLeDevice(false);
}
}
#Override
protected void onDestroy() {
if (mGatt == null) {
return;
}
mGatt.close();
mGatt = null;
super.onDestroy();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == Activity.RESULT_CANCELED) {
//Bluetooth not enabled.
finish();
return;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
// mLEScanner.startScan(filters, settings, mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
line_1.setText(" mLEScanner ");
mLEScanner.startScan(filters, settings, mScanCallback);
}
} else {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
BluetoothDevice btDevice = result.getDevice();
line_2.setText("try connect to " + btDevice.getName());
connectToDevice(btDevice);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
line_2.setText(" batch scan result");
}
}
#Override
public void onScanFailed(int errorCode) {
line_2.setText("scan fail");
}
};
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i("onLeScan", device.toString());
connectToDevice(device);
}
});
}
};
public void connectToDevice(BluetoothDevice device) {
if (mGatt == null) {
try {
BluetoothSocket temp = device.createRfcommSocketToServiceRecord(uuid);
mGatt = device.connectGatt(this, false, gattCallback, TRANSPORT_LE );
} catch( Exception e)
{
}
line_3.setText( device.getAddress());
line_4.setText( "device type: "+ device.getType());
scanLeDevice(false);// will stop after first device detection
}
}
}

Bluetooth low energy using MI BAND 2

I using MI BAND 2 BLE. I made demo app for ready characteristics from BLE. My sample code here
package id.aashari.code.miband2.Activities;
public class MainActivity extends Activity {
Boolean isListeningHeartRate = false;
BluetoothAdapter bluetoothAdapter;
BluetoothGatt bluetoothGatt;
BluetoothDevice bluetoothDevice;
Button btnStartConnecting, btnGetBatteryInfo, btnGetHeartRate, btnWalkingInfo, btnStartVibrate, btnStopVibrate;
EditText txtPhysicalAddress;
TextView txtState, txtByte;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeObjects();
initilaizeComponents();
initializeEvents();
getBoundedDevice();
}
void getBoundedDevice() {
Set<BluetoothDevice> boundedDevice = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice bd : boundedDevice) {
if (bd.getName().contains("MI Band 2")) {
txtPhysicalAddress.setText(bd.getAddress());
}
}
}
void initializeObjects() {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
void initilaizeComponents() {
btnStartConnecting = (Button) findViewById(R.id.btnStartConnecting);
btnGetBatteryInfo = (Button) findViewById(R.id.btnGetBatteryInfo);
btnWalkingInfo = (Button) findViewById(R.id.btnWalkingInfo);
btnStartVibrate = (Button) findViewById(R.id.btnStartVibrate);
btnStopVibrate = (Button) findViewById(R.id.btnStopVibrate);
btnGetHeartRate = (Button) findViewById(R.id.btnGetHeartRate);
txtPhysicalAddress = (EditText) findViewById(R.id.txtPhysicalAddress);
txtState = (TextView) findViewById(R.id.txtState);
txtByte = (TextView) findViewById(R.id.txtByte);
}
void initializeEvents() {
btnStartConnecting.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startConnecting();
}
});
btnGetBatteryInfo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getBatteryStatus();
}
});
btnStartVibrate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startVibrate();
}
});
btnStopVibrate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
stopVibrate();
}
});
btnGetHeartRate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startScanHeartRate();
}
});
}
void startConnecting() {
String address = txtPhysicalAddress.getText().toString();
bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
Log.v("test", "Connecting to " + address);
Log.v("test", "Device name " + bluetoothDevice.getName());
bluetoothGatt = bluetoothDevice.connectGatt(this, true, bluetoothGattCallback);
}
void stateConnected() {
bluetoothGatt.discoverServices();
txtState.setText("Connected");
}
void stateDisconnected() {
bluetoothGatt.disconnect();
txtState.setText("Disconnected");
}
void startScanHeartRate() {
txtByte.setText("...");
BluetoothGattCharacteristic bchar = bluetoothGatt.getService(CustomBluetoothProfile.HeartRate.service)
.getCharacteristic(CustomBluetoothProfile.HeartRate.controlCharacteristic);
bchar.setValue(new byte[]{21, 2, 1});
bluetoothGatt.writeCharacteristic(bchar);
}
void listenHeartRate() {
BluetoothGattCharacteristic bchar = bluetoothGatt.getService(CustomBluetoothProfile.HeartRate.service)
.getCharacteristic(CustomBluetoothProfile.HeartRate.measurementCharacteristic);
bluetoothGatt.setCharacteristicNotification(bchar, true);
BluetoothGattDescriptor descriptor = bchar.getDescriptor(CustomBluetoothProfile.HeartRate.descriptor);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
isListeningHeartRate = true;
}
void getBatteryStatus() {
txtByte.setText("...");
BluetoothGattCharacteristic bchar = bluetoothGatt.getService(CustomBluetoothProfile.Basic.service)
.getCharacteristic(CustomBluetoothProfile.Basic.batteryCharacteristic);
if (!bluetoothGatt.readCharacteristic(bchar)) {
Toast.makeText(this, "Failed get battery info", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(getApplicationContext(),"Successfully readed", Toast.LENGTH_LONG).show();
}
}
void startVibrate() {
BluetoothGattCharacteristic bchar = bluetoothGatt.getService(CustomBluetoothProfile.AlertNotification.service)
.getCharacteristic(CustomBluetoothProfile.AlertNotification.alertCharacteristic);
bchar.setValue(new byte[]{2});
if (!bluetoothGatt.writeCharacteristic(bchar)) {
Toast.makeText(this, "Failed start vibrate", Toast.LENGTH_SHORT).show();
}
}
void stopVibrate() {
BluetoothGattCharacteristic bchar = bluetoothGatt.getService(CustomBluetoothProfile.AlertNotification.service)
.getCharacteristic(CustomBluetoothProfile.AlertNotification.alertCharacteristic);
bchar.setValue(new byte[]{0});
if (!bluetoothGatt.writeCharacteristic(bchar)) {
Toast.makeText(this, "Failed stop vibrate", Toast.LENGTH_SHORT).show();
}
}
final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.v("test", "onConnectionStateChange");
if (newState == BluetoothProfile.STATE_CONNECTED) {
stateConnected();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
stateDisconnected();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
Log.v("test", "onServicesDiscovered");
listenHeartRate();
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.v("test", "onCharacteristicRead");
byte[] data = characteristic.getValue();
txtByte.setText(Arrays.toString(data));
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.v("test", "onCharacteristicWrite");
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
Log.v("test", "onCharacteristicChanged");
byte[] data = characteristic.getValue();
txtByte.setText(Arrays.toString(data));
}
#Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
Log.v("test", "onDescriptorRead");
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.v("test", "onDescriptorWrite");
}
#Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
super.onReliableWriteCompleted(gatt, status);
Log.v("test", "onReliableWriteCompleted");
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
Log.v("test", "onReadRemoteRssi");
}
#Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
Log.v("test", "onMtuChanged");
}
};
}
this is the output
I can read characteristics but it only show byte value I converted into String but it value is always same.example I read battery level it only showing byte type value i attached output screen
I trying to do same with Mi Band 3.
My code is:
private void connect(){
String macAddress = "E9:FD:0C:CB:67:2C";
bleDevice = rxBleClient.getBleDevice(macAddress);
connectDisposable = bleDevice.establishConnection(true)
.subscribe(
rxBleConnection -> {
// All GATT operations are done through the rxBleConnection.
Log.d(TAG, "Is connected");
rxBleConnection.readCharacteristic(UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT).subscribe(
bytes -> {
Log.d(TAG, "Data " + bytes);
},
throwable -> {
Log.d(TAG, "Error " + throwable.getMessage());
}
);
},
throwable -> {
// Handle an error here.
Log.d(TAG, "Error " + throwable.getMessage());
}
);
}
Can you provide any explanations how you solved the problem.

Using BLE - Read GATT characteristics

I'm trying to read GATT characteristic values from a Bluetooth LE device (a Heart Rate bracelet). Its specs are:
Services
Characteristics
I have not yet figured out how to "read" the specifications and "translate" them into code.
I need to show on my app the heartbeats detected by the device. What is the way to read the GATT values? A code example would be much appreciated :)
Follow my actual source code.
SETUP THE BLUETOOT CONNECTION
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
private static final long SCAN_PERIOD = 10000;
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth);
mHandler = new Handler();
// BLE is supported?
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "Bluetooth Low Energy non supportato", Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Bluetooth is supported?
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth non supportato", Toast.LENGTH_SHORT).show();
finish();
}
}
#Override
protected void onResume() {
super.onResume();
// Bluetooth is enabled?
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
scanLeDevice(true);
}
#Override
protected void onPause() {
super.onPause();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
scanLeDevice(false);
}
}
DISCOVER BLE DEVICES AND CONNECT WITH HEART RATE MONITOR
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i(TAG, "Name: " + device.getName() + " (" + device.getAddress() + ")");
String deviceAddress = device.getAddress();
if (deviceAddress.equals("C0:19:37:54:9F:30")) {
connectToDevice(device);
}
}
});
}
};
public void connectToDevice(BluetoothDevice device) {
if (mBluetoothGatt == null) {
Log.i(TAG, "Attempting to connect to device " + device.getName() + " (" + device.getAddress() + ")");
mBluetoothGatt = device.connectGatt(this, true, gattCallback);
scanLeDevice(false);// will stop after first device detection
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i(TAG, "Status: " + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
Log.i(TAG, "STATE_CONNECTED");
//BluetoothDevice device = gatt.getDevice(); // Get device
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e(TAG, "STATE_DISCONNECTED");
break;
default:
Log.e(TAG, "STATE_OTHER");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
List<BluetoothGattService> services = gatt.getServices();
Log.i(TAG, "Services: " + services.toString());
BluetoothGattCharacteristic bpm = services.get(2).getCharacteristics().get(0);
gatt.readCharacteristic(services.get(0).getCharacteristics().get(0));
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
// my attempt to read and print characteristics
byte[] charValue = characteristic.getValue();
byte flag = charValue[0];
Log.i(TAG, "Characteristic: " + flag);
//gatt.disconnect();
}
};
try with this inside gattCallback:
#Override
public synchronized void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
final byte[] dataInput = characteristic.getValue();
}
EDIT
And I think you are going to receive a byte with the hear rate data, use this function to get the int value:
public int unsignedByteToInt(byte b) {
return b & 0xFF;
}
And call it inside onCharacteristicChanged():
final byte[] dataInput = characteristic.getValue();
int hearRate = unsignedByteToInt(dataInput);
EDIT 2
Create a notification listener for the heart rate:
public void setHeartRateNotification(boolean enable){
String uuidHRCharacteristic = "YOUR CHARACTERISTIC";
BluetoothGattService mBluetoothLeService = null;
BluetoothGattCharacteristic mBluetoothGattCharacteristic = null;
for (BluetoothGattService service : mBluetoothGatt.getServices()) {
if ((service == null) || (service.getUuid() == null)) {
continue;
}
if (uuidAccelService.equalsIgnoreCase(service.getUuid().toString())) {
mBluetoothLeService = service;
}
}
if(mBluetoothLeService!=null) {
mBluetoothGattCharacteristic =
mBluetoothLeService.getCharacteristic(UUID.fromString(uuidHRCharacteristic));
}
else{
Log.i("Test","mBluetoothLeService is null");
}
if(mBluetoothGattCharacteristic!=null) {
setCharacteristicNotification(mBluetoothGattCharacteristic, enable);
Log.i("Test","setCharacteristicNotification:"+true);
}
else{
Log.i("Test","mBluetoothGattCharacteristic is null");
}
}
And set it onServiceDiscover inside gattCallback:
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.i("Test", "onServicesDiscovered received: " + status);
setHeartRateNotification(true);
}

How to set buzzer for BLE device in Android

I'm developed Android app to manipulating with BLE device as shown in this
image.
The app can scan and connect the device, but I can't write correct characteristic to buzzer the tag. I write this code to do that:
private static final int ALERT_HIGH = 2;
private static final UUID IMMEDIATE_ALERT_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
private static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
public void ClickButton(View view)
{
BluetoothGattService alertService = mGatt.getService(IMMEDIATE_ALERT_UUID);
if (alertService == null)
{
Toast.makeText(this, "Immediate Alert service not found!", 1)
.show();
return;
}
BluetoothGattCharacteristic alertLevel = alertService.getCharacteristic(ALERT_LEVEL_UUID);
if (alertLevel == null)
{
Toast.makeText(this, "Alert Level charateristic not found!", 1)
.show();
return;
}
alertLevel.setValue(ALERT_HIGH, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mGatt.writeCharacteristic(alertLevel);
}
but no action happened!
I found this app iTracing on play store and it worked fine and it can buzzer the ble device.
I don't know where is the missing in my code; and don't know the problem in a previous function I used or in initialize of connection with this device!
Finally, this is the full code I used
public class MainActivity extends Activity {
private BluetoothAdapter mBluetoothAdapter;
private int REQUEST_ENABLE_BT = 1;
private Handler mHandler;
private static final long SCAN_PERIOD = 1000*60;
private BluetoothLeScanner mLEScanner;
private ScanSettings settings;
private List<ScanFilter> filters;
private BluetoothGatt mGatt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new Handler();
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE Not Supported",
Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
#Override
protected void onResume() {
super.onResume();
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} else {
if (Build.VERSION.SDK_INT >= 21) {
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
filters = new ArrayList<ScanFilter>();
}
scanLeDevice(true);
}
}
#Override
protected void onPause() {
super.onPause();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
scanLeDevice(false);
}
}
#Override
protected void onDestroy() {
if (mGatt == null) {
return;
}
mGatt.close();
mGatt = null;
super.onDestroy();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == Activity.RESULT_CANCELED) {
//Bluetooth not enabled.
finish();
return;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner.startScan(filters, settings, mScanCallback);
}
} else {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.i("callbackType", String.valueOf(callbackType));
Log.i("result", result.toString());
BluetoothDevice btDevice = result.getDevice();
String DeviceAddress = btDevice.getAddress().trim();
if(DeviceAddress.equals("FF:FF:00:01:05:07"))
connectToDevice(btDevice);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
Log.i("ScanResult - Results", sr.toString());
}
}
#Override
public void onScanFailed(int errorCode) {
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i("onLeScan", device.toString());
connectToDevice(device);
}
});
}
};
String address;
public void connectToDevice(BluetoothDevice device) {
if (mGatt == null) {
address = device.getAddress();
mGatt = device.connectGatt(this, false, gattCallback);
}
}
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:
Log.i("gattCallback", "STATE_CONNECTED");
mGatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e("gattCallback", "STATE_DISCONNECTED");
break;
default:
Log.e("gattCallback", "STATE_OTHER");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
List<BluetoothGattService> services = gatt.getServices();
Log.i("onServicesDiscovered", services.toString());
gatt.readCharacteristic(services.get(1).getCharacteristics().get
(0));
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic, int status) {
Log.i("onCharacteristicRead", characteristic.toString());
gatt.disconnect();
}
};
private static final int ALERT_HIGH = 2;
private static final UUID IMMEDIATE_ALERT_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
private static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
public void ClickButton(View view)
{
BluetoothGattService alertService = mGatt.getService(IMMEDIATE_ALERT_UUID);
if (alertService == null)
{
Toast.makeText(this, "Immediate Alert service not found!", 1)
.show();
return;
}
BluetoothGattCharacteristic alertLevel = alertService.getCharacteristic(ALERT_LEVEL_UUID);
if (alertLevel == null)
{
Toast.makeText(this, "Alert Level charateristic not found!", 1)
.show();
return;
}
alertLevel.setValue(ALERT_HIGH, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mGatt.writeCharacteristic(alertLevel);
}
}
I will be grateful for help.
This is how I have done it in my code.
byte[] valToWrite = parseHexStringToBytes("0x0" + alertLevel);
immediateAlertChar.setValue(valToWrite);
boolean val = gatt.writeCharacteristic(immediateAlertChar);
Check also the response in onCharacteristicWrite() method

Categories

Resources