has anyone tried using HM-10 Bluetooth module?
I'm able to pair with it using an Android device and passing the pre-defined PIN. Based on the UART return, the pairing is successful (module returns OK+CONN - means a connection was established)
However, after a few seconds (2-3), the UART receives OK+LOST; means the connection was lost. Also, the LED starts blinking (normally, when a connection is active, it stays lit)
Is this normal behaviour for bluetooth in general or the HM-10 module.
This is the product's website: http://www.jnhuamao.cn/bluetooth.asp?ID=1
I'm not sure, but HM -10 don't support rfcom. It's mean that you must use GATT functionality for communication. Entity of BLE is usage of minimum data package as it possible, so BLE don't hold the connection all times and use something like statuses [attributes].
So, few code lines for example, how work with BLE:
1.
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(DEVICE_ADDR);
That's device initiation, the same like with simple bluetooth, where DEVICE_ADDR is the MAC of your BLE(how to find this address you can find in google or stack overflow, its trivial)
2.
BluetoothGattService mBluetoothGattService;
BluetoothGatt mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt.discoverServices();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
List<BluetoothGattService> gattServices = mBluetoothGatt.getServices();
for(BluetoothGattService gattService : gattServices) {
if("0000ffe0-0000-1000-8000-00805f9b34fb".equals(gattService.getUuid().toString()))
{
mBluetoothGattService = gattService;
}
}
} else {
Log.d(TAG, "onServicesDiscovered received: " + status);
}
}
};
So, what this code mean: if u can see from this part of code, i describe how GATT service find. This service needed for "attribute" communication. gattService.getUuid() has few uuids for communication(4 in my module), some of them used for RX, some for TX etc. "0000ffe0-0000-1000-8000-00805f9b34fb" that is one of uuid that use for communication thats why i check it.
The final part of code is message sending:
BluetoothGattCharacteristic gattCharacteristic = mBluetoothGattService.getCharacteristic(UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
String msg = "HELLO BLE =)";
byte b = 0x00;
byte[] temp = msg.getBytes();
byte[] tx = new byte[temp.length + 1];
tx[0] = b;
for(int i = 0; i < temp.length; i++)
tx[i+1] = temp[i];
gattCharacteristic.setValue(tx);
mBluetoothGatt.writeCharacteristic(gattCharacteristic);
After sending message contain hold on and you can send another message or can close connection.
More info, you can find on https://developer.android.com/guide/topics/connectivity/bluetooth-le.html.
PS: MAC address of your module can find with ble scanner code or with AT cmd:
on my firmware AT+ADDR or AT+LADDR
About UUIDs usage: not sure, but in my case, i find it with next AT+UUID [Get/Set system SERVER_UUID] -> Response +UUID=0xFFE0, AT+CHAR [Get/Set system CHAR_UUID] - Response +CHAR=0xFFE1. Thats why i make conclusion that UUID which i must use fe "0000[ffe0/is 0xFFE0 from AT response]-0000-1000-8000-00805f9b34fb"
Related
My device information
Nordic board :
MTU size : 247.
This board send notification multiple packets in one connection interval (Just counter value like 1,2,3,4...) at "Heart Rate Measurement".
Android device :
Version 5.0 and 6.0. (Using two device).
communicate Bluetooth Low Energy(BLE) with board.
board connect with my Android app MTU is setting 244.
Application source is google sample project BluetoothLeGatt
App send notification value at "Heart Rate Service" characteristic.
Receive notification value at Gattcallback "onCharacteristicChanged()"
Problem
My Android app lost some packet.
I read this post. Maximizing BLE Throughput on iOS and Android. So I send E-mail this post author and I search another information for Android.
I found some similarly question. but that question answer was not work. Then I found one question what I want exactly. but this question have no answers. Android receiving multiple BLE packets per connection interval. Unfortunately I don't have any reply E-mail answer.
My question is how do I set Android BLE notification. (Not Nordic board setting)
(My question is same Android receiving multiple BLE packets per connection interval)
Under line is my sample code. at notification.
#Connect
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
#GattCallback
/*broadcastUpdate method is display value*/
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:");
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected from GATT server.");
mConnectionState = STATE_DISCONNECTED;
broadcastUpdate(ACTION_GATT_DISCONNECTED);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onServicesDiscovered success: (status)" + status);
//findServiceOther(gatt);
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
Log.d(TAG, "Request MTU");
gatt.requestMtu(SET_MTU);
} else {
Log.w(TAG, "onServicesDiscovered failed: (status)" + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onCharRead Success");
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
} else {
Log.d(TAG, "OnCharRead Error: " + status);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (characteristic.getUuid().equals(SampleGattAttributes.UUID_HEART_RATE_MEASUREMENT))
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic, FLAG_HEART_RATE);
else
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
#Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
boolean priority = gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
Log.d(TAG, "MTU changed (mtu/status) / Priority : (" + mtu + "/" + status + ") / " + priority);
changed_MTU_Size = mtu;
broadcastUpdate(ACTION_DATA_AVAILABLE, changed_MTU_Size, FLAG_MTU);
broadcastUpdate(ACTION_GATT_CONNECTED);
}
#set notification
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
if (SampleGattAttributes.UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
// This is specific to Heart Rate Measurement.
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(SampleGattAttributes.UUID_CLIENT_CHARACTERISTIC_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
Edit_1
I test Nordic offical app in Google play store.
nRF Connect for Mobile
but this app miss packet too.
Edit_2
I found some problem too.
< Nordic board constant setting>
HEART_RATE_MEAS_INTERVAL : 10
MIN_CONN_INTERVAL : MSEC_TO_UNITS(40, UNIT_1_25_MS)
MAX_CONN_INTERVAL : MSEC_TO_UNITS(40, UNIT_1_25_MS)
SLAVE_LATENCY 0
CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
< Run in my Android app >
skip requestMTU : receive 20byte packet successful. (Data rate average is 2200byte/second in my app)
requestMTU : I try so many MTU size (ex: 23(can small size), 40, 100, 255(target) ...) but lost some packet (Data rate 8500 ~ 9500 byte/second in my app)
I wonder requestMTU and notification receive interrelation.
i have implemented a file transfer over LE on a nrf51422 and SD310 by using the Nordic UART Service. The android App is written in CPP by using Qt and the QtBluetooth library. Therefore, this answer my not really help you. But, i have taken some afford to achive a usable data rate. 1st, set the connection parameters to 7.5ms (min) and 15ms (max). 2nd, on the peripheral side, i send up to 7 packets (til the buffer is full). So the peripheral send up to 7 packets per connection event.
On the Android side, the charachteritic changed event arrive me frequently with a data size of 20 bytes (due to the maximum MTU size of 23, 3 bytes used by nordic uart service) and i read the data instantly.
Perhaps your mistake is the MTU size of 244. The default BLE MTU size is 23 (Core spec 4.1).
Regards
I'm trying to connect programmatically my device to for example on my Headsets... I had KitKat version and all worked perfect (Bluetooth always was connecting without problems autommatically) but since I've updated to Lolipop it doesn't. I'd like to know if there is any way to connect any paired device of my Android phone to Bluetooth when it turns on.
Since now I've this code (gets the Device name and Device Address) because I thought with it I could connect doing something like device.connect(MAC-Address); but it didn't work...
BluetoothAdapter bluetoothAdapter
= BluetoothAdapter.getDefaultAdapter();
Set < BluetoothDevice > pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device: pairedDevices) {
mDeviceName.add(device.getName());
mDeviceMAC.add(device.getAddress());
}
}
bluetoothClass.setDeviceName(mDeviceName);
bluetoothClass.setDeviceMac(mDeviceMAC);
Question
On my MotoG (KitKat) if I turn my Bluetooth it connects autommatically to device (if it's near and paired ofc...) but on my LG G3 I must go to Configuration/Bluetooth/Paired devices/ and there tap the device to connect... and I want to avoid this... should be possible?
I would like to know if there is any possibility to connect to specific Bluetooth just adding the Device name or Device MAC... More or less like Android does when I click on my device to connect it connects autommatically... I just want to get that CLICK event.
I know that Android should connect autommatically to a paired device but there's any exceptions that doesn not ... the only way to pair it it's doing the click... that's why I'm wondering if it's there a way to do it...
I've read and tested kcoppock answer but it still don't work ..
Any suggestion?
EDIT
The main thing that I wanted to do is to connect my Bluetooth autommatically but since I've read on Hey you answer... I figured it out and I know it's an Android bug, so the thing that I would like to do is select the paired devices and then click on the device that I want to connect (Without doing any Intent) and connect it, instead to go Configuration/Bluetooth/....
Btw I've read any answers on StackOverflow and I found something with Sockets are they used to connect Bluetooth?Could be it a solution?
Edit to answer latest question
You can avoid using an intent to search for paired devices. When connecting to a device that is not paired, a notification will pop up asking to pair the devices. Once paired this message should not show again for these devices, the connection should be automatic (according to how you have written your program).
I use an intent to enable bluetooth, and to make my device discoverable, I then set up my code to connect, and press a button to connect. In your case, you will need to ensure your accessories are discoverable also. In my case I use a unique UUID, and both devices must recognise this to connect. This can only be used if you are programming both devices, whether both are android or one android and one other device type.
Try this, and see if it solves your problem.
This answer is to the original question before it was edited to be another question.
I've edited my answer for clarity as I can see from the comments it is misleading. Your question has two parts.
On my MotoG (KitKat) if I turn my Bluetooth it connects autommatically
to device (if it's near and paired ofc...) but on my LG G3 I must go
to Configuration/Bluetooth/Paired devices/ and there tap the device to
connect... and I want to avoid this... should be possible?
This is less of a programming issue and more of a platform issue.
There is a well documented bug in Android 5.0 with Bluetooth not automatically connecting and many other BT issues. These issues continue with all the updates on 5.0. versions and is not fixed until the 5.1. upgrade.
http://www.digitaltrends.com/mobile/android-lollipop-problems/11/
http://forums.androidcentral.com/lg-g3/473064-bluetooth-streaming-choppy-lg-3-lollipop.html
First port of call is to update to 5.1
These issues have been addressed in the Lollipop update 5.1
http://www.reddit.com/r/Android/comments/306m3y/lollipop_51_bluetooth/
Edit:
I don't believe this is going to fix your problem of the automatic pairing, you wanted to know how to use BTGatt.
I've seen if I type device. to check what can I do it let me
connectGatt() means /.../
But I can't figure it out how to do this...
To use BluetoothGatt
https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html
This class provides Bluetooth GATT functionality to enable
communication with Bluetooth Smart or Smart Ready devices.
/.../
GATT capable devices can be discovered using the Bluetooth device
discovery or BLE scan process.
https://developer.android.com/reference/android/bluetooth/BluetoothGattCallback.html
Here is a great example of how to use BluetoothGatt (it uses hear rate):
https://github.com/googlesamples/android-BluetoothLeGatt/blob/master/Application/src/main/java/com/example/android/bluetoothlegatt/BluetoothLeService.java
I have reproduced some of the code here, in case the link dies.
It basically follows similar lines to a regular bluetooth connection. You need to discover and find supported devices.
Monitor state, etc.
These are the two most pertinent features to gatt.
The callback:
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
The broadcast:
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Heart rate format UINT8.");
}
final int heartRate = characteristic.getIntValue(format, 1);
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
} else {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
}
}
sendBroadcast(intent);
}
This question also has some relevant code that may help cut it down when learning:
BLuetooth Gatt Callback not working with new API for Lollipop
Now here's the rub. Are your devices bluetooth smart or smart ready?
This link gives a great list of smart devices. You will also find out when you implement your program.
http://www.bluetooth.com/Pages/Bluetooth-Smart-Devices-List.aspx
This is how i made this work using Java Reflection and BluetoothProfile:
Attributes:
private boolean mIsConnect = true;
private BluetoothDevice mDevice;
private BluetoothA2dp mBluetoothA2DP;
private BluetoothHeadset mBluetoothHeadset;
private BluetoothHealth mBluetoothHealth;
Call:
mBluetoothAdapter.getProfileProxy(getApplicationContext() , mProfileListener, BluetoothProfile.A2DP);
mBluetoothAdapter.getProfileProxy(getApplicationContext() , mProfileListener, BluetoothProfile.HEADSET);
mBluetoothAdapter.getProfileProxy(getApplicationContext() , mProfileListener, BluetoothProfile.HEALTH);
Listener:
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.A2DP) {
mBluetoothA2DP = (BluetoothA2dp) proxy;
try {
if (mIsConnect) {
Method connect = BluetoothA2dp.class.getDeclaredMethod("connect", BluetoothDevice.class);
connect.setAccessible(true);
connect.invoke(mBluetoothA2DP, mDevice);
} else {
Method disconnect = BluetoothA2dp.class.getDeclaredMethod("disconnect", BluetoothDevice.class);
disconnect.setAccessible(true);
disconnect.invoke(mBluetoothA2DP, mDevice);
}
}catch (Exception e){
} finally {
}
} else if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = (BluetoothHeadset) proxy;
try {
if (mIsConnect) {
Method connect = BluetoothHeadset.class.getDeclaredMethod("connect", BluetoothDevice.class);
connect.setAccessible(true);
connect.invoke(mBluetoothHeadset, mDevice);
} else {
Method disconnect = BluetoothHeadset.class.getDeclaredMethod("disconnect", BluetoothDevice.class);
disconnect.setAccessible(true);
disconnect.invoke(mBluetoothHeadset, mDevice);
}
}catch (Exception e){
} finally {
}
} else if (profile == BluetoothProfile.HEALTH) {
mBluetoothHealth = (BluetoothHealth) proxy;
try {
if (mIsConnect) {
Method connect = BluetoothHealth.class.getDeclaredMethod("connect", BluetoothDevice.class);
connect.setAccessible(true);
connect.invoke(mBluetoothHealth, mDevice);
} else {
Method disconnect = BluetoothHealth.class.getDeclaredMethod("disconnect", BluetoothDevice.class);
disconnect.setAccessible(true);
disconnect.invoke(mBluetoothHealth, mDevice);
}
}catch (Exception e){
} finally {
}
}
}
public void onServiceDisconnected(int profile) {
}
};
I hope this helps anyone trying to connect to Bluetooth Audio devices and headsets.
I want to get the value of the HRM of an "A&D UA-651BLE" device.
this is what's written in the datasheet of this device to get the HRM value:
Set the application to pairing mode to start scanning.
Start pairing of A&D BLE device following each instruction manual.
At pairing mode, the application should set time and date and any other device settings
to A&D BLE device. After successful pairing, A&D BLE device shows “End” on the screen.
Take a measurement and finish the measurement, then A&D BLE device start BLE
connection with advertising. The application starts scanning with suitable interval so that
the application catches the advertising of A&D BLE device as soon as it can.
At initial connection or pairing, the Application set “2” to CCCD (Client Characteristic
Configuration Descriptor) so that A&D BLE device sends a measurement data with
Indication.
After A&D device recognizes to be set “2” to CCCD and to be synchronized time and date
within 5 seconds after connected, send the data with Indication.
If the timeout set CCCD and time and date is expired, A&D BLE device will not send data
and store the data in memory. The stored data in A&D BLE device can send next
successful connection.
this is my service code:
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
and this is the method that read data:
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
Log.e("HRM value",stringBuilder.toString());
dataComposition.put(characteristic.getUuid().toString(),stringBuilder.toString());
intent.putExtra(EXTRA_DATA,dataComposition);
}
the problem is that this code doesn't return any data !!
There's an Android Open Source Project example that does precisely this, easiest option would be to clone the android-BluetoothLeGatt code, build and compare it to your own. If you can't spot the difference / issue simply deploy both app's and step through both sets of code. Having some known working code will also help to rule out the possibility that the HRM is not functioning properly.
Do you have and example , i try this with equal device and i cant obtain the information y try with
public String response() {
if (mConnected) {
mBluetoothLeService.readCharacteristic(characteristica);
byte response[] = characteristica.getValue();
String respuesta = ReadBytes(response);
mBluetoothLeService.disconnect();
return respuesta;
} else {
return null;
}
}
I connect to my Bluetooth Low Energy device like it's described in : https://developer.android.com/guide/topics/connectivity/bluetooth-le.html
I get device:
#Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
if(device.getName().startsWith("BLE device")){
mDevice = device;
mDevice.connectGatt(RGBLight.this, false, bgc);
}
}
Getting a gatt from Device:
public void onConnectionStateChange(final android.bluetooth.BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
//My app should keep connection to the BLE device as long as app lives.
RGBLight.this.gatt = gatt;
gatt.discoverServices();
}
}
3.When gatt is connected and services are discovered i'm trying to send a messages queue to the characteristic.
new Thread(new Runnable() {
#Override
public void run() {
if (mService == null)
mService = gatt.getService(UUID_SERVICE);
if (mCharacteristic == null)
mCharacteristic = mService.getCharacteristic(UUID_CHAR);
for(int i = 0; i < 100; i++){
int r = Color.red(colorParsed);
int g = Color.green(colorParsed);
int b = Color.blue(colorParsed);
int br = Color.blue(brParsed);
mCharacteristic.setValue(new byte[] { COMMAND_SET_RGBW, (byte) r, (byte) g, (byte) b, (byte) br, 0, 0, 0, 0 });
gatt.writeCharacteristic(mCharacteristic);
TimeUnit.MILLISECONDS.sleep(100);
}
}
}).start();
When i run this code, most of commands are missed. Execution speed is about 1 command per second. And there is an error in LogCat:
06-23 12:34:25.627: E/bt-btif(18002): already has a pending command!!
This low speed worsens user experience of my app.
I investigated a few days and found very interesting behavior. If I start the app and quickly send message queue, it works fast.(1 command per 100ms). But after 10-15 seconds after start it begin to slow down and error message occures again:
06-23 12:34:25.627: E/bt-btif(18002): already has a pending command!!
Maybe someone already faced with a such problem and there is a way to reset a message queue with Android API or something else.
You MUST wait for onCharacteristicWritten before you continue or you flood the buffers. That gatt.write characteristic returns merely means it is on its way through the ble stack and air.
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.