write with Bluetooth Low Energy - android

I am working in an app for Android that uses BLE. I want to write inside a characteristic of the device Service that I am connected to.
My function is this:
public void writeCharacteristic(BluetoothGattCharacteristic characteristic,
boolean enabled, String text) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
characteristic.setValue("7");
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
}
I do not why the value is not written inside the characteristic.
I followed the steps in this link:
write with BLE
anyone knows why my code does not work?
Thank you very much.
Regards
P.D. apologies for my English.

Maybe your characteristic accepts a byte[] value. Try setting the characteristic value with byte array by converting String parameter into byte[]. Your method should be like this:
public void writeCharacteristic(BluetoothGattCharacteristic characteristic,
String text) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
byte[] data = hexStringToByteArray(text);
characteristic.setValue(data);
boolean status = mBluetoothGatt.writeCharacteristic(characteristic);
}
private byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character
.digit(s.charAt(i + 1), 16));
}
return data;
}
Also note that, status variable returns true, if the write operation was initiated successfully. So, in order to get write operation result status use onCharacteristicWrite callback of BluetoothGattCallback and check the status in it.

After spending all morning at the computer trying different functions and forms, I found the solution thanks to a friend from work.
We have to convert the text to byte, then put that byte into a byte array and send. Fixed.
byte pepe = (byte) Integer.parseInt(text);
byte[] charLetra = new byte[1];
charLetra[0] = pepe;
LumChar.setValue(charLetra);
boolean status = mBluetoothGatt.writeCharacteristic(LumChar);
Anyway thank you very much for your help.
Regards.

Related

How to manage a multiple BLE writeCharacteristic and readCharacteristic call?

I am currently working to Android application which communicates with a CC2650 Bluetooth Low Energy (BLE) device.
I have to need to make a writeCharacteristic call followed by multiple readCharacteristic calls with a function. This order can be reversed without affecting functionality.
Question 1: When only a writeCharacteristic or readCharacteristic are called individually the software works as expected. But software doesn't seem to work when the calls are made in sequence.
Below is the code.
Code section referencing writeCharacteristic code (UI Thread)
final BluetoothGattCharacteristic characteristic_select = mGattCharacteristicMap.get("hotstate");
if (characteristic_select != null) {
final int charaProp = characteristic_select.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
String strData = "00";
int len = strData.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(strData.charAt(i), 16) << 4)
+ Character.digit(strData.charAt(i + 1), 16));
}
characteristic_select.setValue(data);
mBLE_Service.writeCharacteristic(characteristic_select);
}
}
Code section with readCharacteristic (UI Thread). Note Multiple read call, which are queued
final BluetoothGattCharacteristic characteristic_time = mGattCharacteristicMap.get("timestate");
if (characteristic_time != null) {
final int charaProp = characteristic_time.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
for (int i = 0; i < 10; i++) {
mBLE_Service.readCharacteristic(characteristic_time);
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
}
}, 5000);
}
}
}
Code for readCharacteristic
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
// Queue the characteristic to read, since several reads are done on startup
characteristicQueue.add(characteristic);
// If there is only 1 item in the queue, then read it. If more than 1, it is handled
// asynchronously in the callback
if((characteristicQueue.size() <= 1)) {
mBluetoothGatt.readCharacteristic(characteristic);
}
}
Code for writeCharacteristic
public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.writeCharacteristic(characteristic);
}
Code for onCharacteristicRead
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
// Read action has finished, remove from queue
characteristicQueue.remove();
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
// Handle the next element from the queues
if(characteristicQueue.size() > 0)
mBluetoothGatt.readCharacteristic(characteristicQueue.element());
else if(descriptorWriteQueue.size() > 0)
mBluetoothGatt.writeDescriptor(descriptorWriteQueue.element());
}
Code for onCharacteristicWrite
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status==BluetoothGatt.GATT_SUCCESS){
broadcastUpdate(ACTION_WRITE_SUCCESS, characteristic);
}
}
Question 2: Since I have multiple reads I created a queue to handle. Do you think read and write are causing the issue? If so any suggestion on how to manage and block reads and writes?
Note: Code is for Android API 21 and higher
References:
What is “reliable write” in BLE?
onCharacteristicWrite() is being called, but it doesn't always write
You are half-way there by understanding you need a queue. But you must make sure you use it for ALL GATT operations. See my full answer: Android BLE BluetoothGatt.writeDescriptor() return sometimes false.
This is because you need to wait for the callback to return before writing/reading again. Similar problem for the answer here.
Android BLE BluetoothGattDescriptor writeDescriptor issue
Except instead you may need to wait for the readDescriptor/Characteristic in addition to the write.

How to write hex value to BLE device?

I have a BLE device prototype. I am able to scan the device, connect to it. I am also able to write its password as BLE characteristic . Password is in String. But when I am trying to write other values which are in hex it is giving me write unsuccessful error with status 4 and status 13 at different times ? The same thing is working with nRF application. Where am I going wrong. Below is my code.
public boolean writeCharacteristic(BluetoothGatt mBluetoothGatt) {
//check mBluetoothGatt is available
if (mBluetoothGatt == null) {
Log.e("++++", "lost connection");
return false;
}
String SERVICE_STRING = "3fc2d576-0249-11e7-93ae-----------";
UUID SERVICE_UUID = UUID.fromString(SERVICE_STRING);
BluetoothGattService Service = mBluetoothGatt.getService(SERVICE_UUID);
if (Service == null) {
Log.e("++++++", "service not found!");
return false;
}
BluetoothGattCharacteristic charac = Service
.getCharacteristic(UUID.fromString("3fc2d576-0249-11e7-93ae-------------"));
if (charac == null) {
Log.e("+++", "char not found!");
return false;
}
String mValue = "0x01";
byte[] value = mValue.getBytes();
//value[0] = (byte) (0x00);
String pwd = "WWW";
// byte[] value = mValue.getBytes();
charac.setValue(0x01,BluetoothGattCharacteristic.FORMAT_SINT8,0);
boolean status = mBluetoothGatt.writeCharacteristic(charac);
return status;
}
Let's change charac.setValue(0x01,BluetoothGattCharacteristic.FORMAT_SINT‌​8,0); into charac.setValue(new byte[]{0x01});

Sending hex values through a BluetoothLE connection

I am a novice in android development, so please forgive if the descriptions are not totally correct.
I am using the Android BTLE example app as a template and am attempting to send simple hex values to a Microchip RN4020 module. I can successfully send data (specifically time data using the calendar function) and they appear on my PuTTY window. However the problem is that the data is being 'transmitted' from the application (on my Samsung j5) as an ASCII representation.... in other words, the Calendar function returns the minute as say 20 (20hex = 32 decimal), which is somehow ending up as ASCII 20 on my PuTTY terminal (i.e. 32 30).
I am sending the data as a Byte array, which as I understand it constrains the range of values to be -127 to +127. So to combat this I have attempted to break the value into upper and lower nibbles and send these as separate bytes.....same problem. The value appearing is the ASCII 2 0....(i.e. 32 30).
I have taken the liberty of posting below my code (apologies for the 'clunkiness' of it). I strongly suspect it is a really rudimentary error, but I cant find how to transmit the 'hex values' Please help
regards
J
public void onClickTest(View v){
if(mBluetoothLeService != null) {
Calendar calendar = Calendar.getInstance();
//Data_1[0] = (Integer.toHexString((byte)calendar.get(Calendar.SECOND) & 0xFF)); //Alarm Set
int temp = 0;
int temp1 = 0;
byte first = 0;
byte second = 0;
temp = calendar.get(Calendar.HOUR_OF_DAY);
temp1 = temp;
temp = temp & 0xf0;
temp = temp >> 4;
temp1 = temp1 & 0x0f;
first = (byte)temp;
second = (byte)temp1;
Data_1[0] = first;
Data_1[1] = second; //Alarm Set
//Data_1[1] = 0xff; //Update clock
// Data_1[2] = calendar.get(Calendar.SECOND);
// Data_1[2] = calendar.get(Calendar.SECOND);
// Data_1[3] = (char)calendar.get(Calendar.MINUTE);
// Data_1[4] = (char)calendar.get(Calendar.HOUR_OF_DAY);
// Data_1[5] = (byte)calendar.get(Calendar.DAY_OF_WEEK);
// Data_1[6] = (byte)calendar.get(Calendar.MONTH);
// Data_1[7] = (byte)calendar.get(Calendar.YEAR);
//myArray = (Arrays.toString(Data_1));
mBluetoothLeService.writeCustomCharacteristicString(Data_1);
This is the actual LE service bit
public void writeCustomCharacteristicString(byte[] value) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService1 = mBluetoothGatt.getService(UUID.fromString("12345678-9012-3456-7890-1234567890FF"));
if(mCustomService1 == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic1 = mCustomService1.getCharacteristic(UUID.fromString("12345678-9012-3456-7890-123456789011"));
mWriteCharacteristic1.setValue(value);
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic1) == false){
Log.w(TAG, "Failed to write characteristic");
}
}

How to send data over a Bluetooth Low Energy (BLE) link?

I am able to discover, connect to bluetooth.
Source Code---
Connect via bluetooth to Remote Device:
//Get the device by its serial number
bdDevice = mBluetoothAdapter.getRemoteDevice(blackBox);
//for ble connection
bdDevice.connectGatt(getApplicationContext(), true, mGattCallback);
Gatt CallBack for Status:
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
//Connection established
if (status == BluetoothGatt.GATT_SUCCESS
&& newState == BluetoothProfile.STATE_CONNECTED) {
//Discover services
gatt.discoverServices();
} else if (status == BluetoothGatt.GATT_SUCCESS
&& newState == BluetoothProfile.STATE_DISCONNECTED) {
//Handle a disconnect event
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
//Now we can start reading/writing characteristics
}
};
Now I want to send commands to Remote BLE device but don't know how to do that.
Once the command is sent to the BLE device, the BLE device will respond by broadcasting
data which my application can receive.
You need to break this process into a few steps, when you connect to a BLE device and discover Services:
Display available gattServices in onServicesDiscovered for your callback
To check whether you can write a characteristic or not
check for BluetoothGattCharacteristic PROPERTIES -I didn't realize that need to enable the PROPERTY_WRITE on the BLE hardware and that wasted a lot of time.
When you write a characteristic, does the hardware perform any action to explicitly indicate the operation (in my case i was lighting an led)
Suppose mWriteCharacteristic is a BluetoothGattCharacteristic
The part where to check the PROPERTY should be like:
if (((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) |
(charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) > 0) {
// writing characteristic functions
mWriteCharacteristic = characteristic;
}
And, to write your characteristic:
// "str" is the string or character you want to write
byte[] strBytes = str.getBytes();
byte[] bytes = activity.mWriteCharacteristic.getValue();
YourActivity.this.mWriteCharacteristic.setValue(bytes);
YourActivity.this.writeCharacteristic(YourActivity.this.mWriteCharacteristic);
Those are the useful parts of the code that you need to implement precisely.
Refer this github project for an implementation with just a basic demo.
A noob-friendly guide to make Android interact with a LED-lamp.
Step 1.
Get an tool to scan your BLE device. I used "Bluetooth LE Lab" for Win10, but this one will do it as well: https://play.google.com/store/apps/details?id=com.macdom.ble.blescanner
Step 2.
Analyse the behavior of the BLE device by entering data, I recommend to enter hex values.
Step 3.
Get the sample of the Android docs. https://github.com/googlesamples/android-BluetoothLeGatt
Step 4.
Modify the UUIDs you find in SampleGattAttributes
My config:
public static String CUSTOM_SERVICE = "0000ffe5-0000-1000-8000-00805f9b34fb";
public static String CLIENT_CHARACTERISTIC_CONFIG = "0000ffe9-0000-1000-8000-00805f9b34fb";
private static HashMap<String, String> attributes = new HashMap();
static {
attributes.put(CUSTOM_SERVICE, CLIENT_CHARACTERISTIC_CONFIG);
attributes.put(CLIENT_CHARACTERISTIC_CONFIG, "LED");
}
Step 5.
In BluetoothService.java modify onServicesDiscovered:
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
for (BluetoothGattService gattService : gatt.getServices()) {
Log.i(TAG, "onServicesDiscovered: ---------------------");
Log.i(TAG, "onServicesDiscovered: service=" + gattService.getUuid());
for (BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
Log.i(TAG, "onServicesDiscovered: characteristic=" + characteristic.getUuid());
if (characteristic.getUuid().toString().equals("0000ffe9-0000-1000-8000-00805f9b34fb")) {
Log.w(TAG, "onServicesDiscovered: found LED");
String originalString = "560D0F0600F0AA";
byte[] b = hexStringToByteArray(originalString);
characteristic.setValue(b); // call this BEFORE(!) you 'write' any stuff to the server
mBluetoothGatt.writeCharacteristic(characteristic);
Log.i(TAG, "onServicesDiscovered: , write bytes?! " + Utils.byteToHexStr(b));
}
}
}
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
Convert the byte-String using this function:
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
PS: The above code is far away from production, but I hope it helps those, who are new to BLE.

BLE Answer after writing over GATT in Android

Is there a way to come an answer after writing a hex command via Bluetooth Low Energy in android? I write the hex command over gatt, this is my write function:
/* set new value for particular characteristic */
public void writeDataToCharacteristic(final BluetoothGattCharacteristic ch, final byte[] dataToWrite) {
if (mBluetoothAdapter == null || mBluetoothGatt == null || ch == null) return;
// first set it locally....
ch.setValue(dataToWrite);
// ... and then "commit" changes to the peripheral
mBluetoothGatt.writeCharacteristic(ch);
}
After the write is completed the Callback tells me only it's succesfull or it's failed, but the receiver sends an answer back. In moment there is only the check it's succesfull or not, but I wan't to display the answer from receiver. Is there a way to show the answer?
/*The callback function*/
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
String deviceName = gatt.getDevice().getName();
String serviceName = BleNamesResolver.resolveServiceName(characteristic.getService().getUuid().toString().toLowerCase(Locale.getDefault()));
String charName = BleNamesResolver.resolveCharacteristicName(characteristic.getUuid().toString().toLowerCase(Locale.getDefault()));
String description = "Device: " + deviceName + " Service: " + serviceName + " Characteristic: " + charName;
// we got response regarding our request to write new value to the characteristic
// let see if it failed or not
if(status == BluetoothGatt.GATT_SUCCESS) {
mUiCallback.uiSuccessfulWrite(mBluetoothGatt, mBluetoothDevice, mBluetoothSelectedService, characteristic, description);
}
else {
mUiCallback.uiFailedWrite(mBluetoothGatt, mBluetoothDevice, mBluetoothSelectedService, characteristic, description + " STATUS = " + status);
}
};
In your callback have you tried
characteristic.getValue() ?
If this value is different from the one you set and sent across this could be the response you're looking for.
Also, make sure that the Characteristic you're writing to has read or notifiable properties. You can do this as follows:
int props = characteristic.getProperties();
String propertiesString = String.format("0x%04X ", props);
if((props & BluetoothGattCharacteristic.PROPERTY_READ) != 0) propertiesString += "read ";
if((props & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) propertiesString += "write ";
if((props & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) propertiesString += "notify ";
if((props & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) propertiesString += "indicate ";
It's possible there are two Characteristics for a service - one that's writeable (for sending data) and one that's Notifiable for receiving data. That makes it possible for the receiver to do asynchronous processing. Make sure that there isn't another Characteristic in the Service that's Notifiable or Readable

Categories

Resources