I'm trying to connect to an Arduino Uno via an android app using Bluetooth Low Energy (BLE).
I'm developing on Android Studio, testing with a Samsung Galaxy S4, and with an Android version 5.0.1
I followed this link: http://www.truiton.com/2015/04/android-bluetooth-low-energy-ble-example/
I'm scanning devices and when I found one, I would like to get it's UUID before connecting to it, to make sure that it's the right type of device:
mScanCallback = new ScanCallback() {
#Override
#TargetApi(21)
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice btDevice = result.getDevice();
ParcelUuid[] uuids = btDevice.getUuids(); //<-- this is always null!! :(
Log.d(TAG, ""+btDevice.fetchUuidsWithSdp()); //<-- prints true.
Log.d(TAG, "result : " + result.toString()); //<-- prints a bunch of relevant info that contains the UUID I want to check.
Log.d(TAG, "uuids : " + uuids); //<-- prints null.
/*
for (ParcelUuid u : uuids) {
//Compare with the UUID of my device, and connect if ok.
}
*/
}
However, btDevice.getUuids(); is always returning null with no error...
How can I get the UUID of the scanned device?
A brute force method would be to use regexp with the result.toString() to grab what I want but there must be a better way isn't it?
Thanks
BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
// scan for devices
scanner.startScan(new ScanCallback() {
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public void onScanResult(int callbackType, ScanResult result)
{
List<ParcelUuid> uuids = result.getScanRecord().getServiceUuids();
}
}
this is worked for me in Android 6.0.1
After hours of searching I find out that getUuid() is not the way to go if you want to retrieve the uuid of an iBeacon.
If that is the case, you need to get it directly from the Scan result result object.
I managed to work by using the answer provided by ADEBAYO OSIPITAN.
BLE obtain uuid encoded in advertising packet
Here is his code snipet:
//For APIs greater than 21, Returns Device UUID
public String getUUID(ScanResult result){
String UUIDx = UUID
.nameUUIDFromBytes(result.getScanRecord().getBytes()).toString();
return UUIDx;
}
From Java DOC:
public ParcelUuid[] getUuids ()
Added in API level 15
Returns the supported features (UUIDs) of the remote device.
This method does not start a service discovery procedure to retrieve the UUIDs from the remote device. Instead, the local cached copy of the service UUIDs are returned.
Use fetchUuidsWithSdp() if fresh UUIDs are desired.
Requires BLUETOOTH.
Returns
the supported features (UUIDs) of the remote device, or null on error
Your ScanResult probably is a error
Related
I am implementing BLE in Android Studio. I have connected with the peripheral device ok. In my onServicesDiscovered method I want to analyze the services (and characteristics) and I get something like the following when I print out:
android.bluetooth.BluetoothGattService#41b6dd18
There is 4 services in the list and they all look similar except for the numbers at the end. How can I convert this to useful information. I have seen no reference to this format.
Thanks.
Try to read the uuid from the BluetoothGattService object.
You can find uuid of standard services on Bluetooth SIG website. If the uuid is not there (i.e. custom services), you should read the manual of the peripheral or reach out the peripheral maker.
That depends on what you consider "useful" information.
BLE works mostly like dictionary where you look up long numbers (characteristics) and get binary data, so without prior information about the device you're working on, there is not much you can see when you discover services.
That said, in the BLE docs, there is a method displayGattServices() which puts the discovered services info in an ExpandableListView, and here I changed it to print the UUIDs of services and characteristics to logcat instead.
Besides the UUIDs, you can use getProperties() to find out other characteristic properties such as the format of the characteristic data, or getPermissions() to see whether you can read or write the characteristic.
// Demonstrates how to iterate through the supported GATT
// Services/Characteristics.
private void displayGattServices(List<BluetoothGattService> gattServices) {
final String TAG = "BleServiceInfo";
if (gattServices == null) return;
String uuid;
String unknownServiceString = "Unknown service"
String unknownCharaString = "Unknown characteristic"
// Loops through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
Log.d(TAG, "Service: " + gattService.getUuid().toString());
// Loops through available Characteristics.
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
Log.d(TAG, "\tCharacteristic: " + gattCharacteristic.getUuid().toString());
}
}
}
Call this method from onServicesDisccovered() like this:
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
....
displayGattServices(gatt.getServices());
}
I have paired my device to the Android phone explicitly, via an app. This device is a MI-Band 2, and it is paired using the MI-FIT app. I am currently connecting to bluetooth devices using this code:
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
However, the problem is that if the MI-band is connected via the mi-fit app, I cannot get the RSSI value from the MI-Band.
Is it possible to get the RSSI value of explicitly paired devices in Android? If so, what am I doing wrong?
Thanks
Edit: It seems like I can't get RSSI values of any connected devices. For example, if Android phone A is connected to Android Phone B, then I can't read the RSSI values when trying to read via the above code from Phone A.
If you know for sure the bluetooth name of device to be connected, maybe you can try using BluetoothAdapter.LeScanCallback to get noticed when it's scanned. Or do you really need to tell scanned or connected apart?
BluetoothManager bleManager = (BluetoothManager) getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bleAdapter = bleManager.getAdapter();
bleAdapter.startLeScan(leScanCallback);// find match device
BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, final int rssi, byte[] scanRecord) {
if (device.getName() == null || !device.getName().equals("your bluetooth device name")) {
return;
}
// here you can get rssi of specified bluetooth device if it's available.
// and try to connect it programmatically.
connect(device.getAddress());
}
};
I am trying to scan BLE devices with
mBluetoothAdapter.startLeScan(this);
(I know its obsolete for newer versions but just to see it works with my phone [4.4], I am using it). So it starts scanning and then moves on without giving errors but no device is detected. OnLEScan event is also fired but the device parameter in it is null. My LE device is right there and connected.
On googling, I found this happens if the BluetoothAdapter doesnot have a UUID.
How do I set UUID? When is OnLeScan called/fired? Is there any other solution?
My callback code goes here
//BluetoothAdapte.LEScanCallBack on MainActivity
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord){
Log.i(TAG, "New LE Device: " + device.getName() + "#" + rssi);
if(Device_Name.equals(device.getName())){
mDevices.put(device.hashCode(), device);
invalidateOptionsMenu();
}
}
Use this code as it will provide you insight of all the data
available in your BLE device (will display the data in logs).
UUIDs are basically provided by the manufacturer of the device and you can't set it on your own.
For Instance : I was using BLE Beacons and its manufacturer provided me the API which helped me to fetch its UUID.
Sometimes, a special ID is available on the device itself(factory id in my case) which can help you to retrieve your UUID and that too from the manufacturer's website or API.
BluetoothAdapter bluetoothAdapter;
BluetoothLeScanner bluetoothLeScanner;
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
String s = "\nRssi : "+result.getRssi()+"" +
"\nName (Get Device) : "+result.getDevice().getName()+"" +
"\nBytes"+result.getScanRecord().getBytes()+"" +
"\nGet Device : " + result.getDevice()+"" +
"\nAddress : "+result.getDevice().getAddress()+"" +
"\nService UUIds : "+result.getScanRecord().getServiceUuids().get(0)+"" + //Unique
"\nName (Scan Record) : "+result.getScanRecord().getDeviceName()+"" +
"\nUuids device : "+result.getDevice().getUuids()+"" +
"\nDescribe contents : "+result.describeContents();
//This will show you all the data in logs.
Log.e("All Data",s);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
});
}
Anroid 4.4 is not compatible, i used android 5.1 device and it worked like a charm!
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'm currently working on an Android application that connects to an instrument via Bluetooth and need to write string commands and receive string responses back. Currently I have the connect/read/write working for TCP/IP over Wi-Fi and now trying to implement Bluetooth. But I am running into some roadblocks. I have been searching the web trying to find examples of something similar and haven't had any luck. I have been using the Android developer resource example: Bluetooth Chat as my main reference point.
My current code seems to work.. Then it throws a Service Discovery Failed exception at the point of the connection. I am using the DeviceListActivity class to do the discovery and selecting of the device I want to connect to. It returns anActivityResult and then my Bluetooth class waits for it to handle that and then does the connect to it. The code beneath is almost identical to the Bluetooth Chat App.
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(!m_BluetoothAdapter.isEnabled())
{
m_BluetoothAdapter.enable();
}
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BLuetoothDevice object
BluetoothDevice device = m_BluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
connect(device);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
}
else {
// User did not enable Bluetooth or an error occured
Toast.makeText(this, "Bluetooth not enabled", Toast.LENGTH_SHORT).show();
finish();
}
}
}
This is my connect function:
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private void connect(BluetoothDevice device) {
m_Device = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
}
catch (IOException e) {
}
m_Socket = tmp;
m_BluetoothAdapter.cancelDiscovery();
try {
// This is a blocking call and will only return on a
// successful connection or an exception
m_Socket.connect();
}
catch (IOException e) {
try {
m_Socket.close();
}
catch (IOException e2) {
}
return;
}
}
Hopefully, whatever I am doing wrong is simple, but I'm afraid it's never that easy. This is my first time doing any Bluetooth development, and maybe I'm doing something blatantly wrong... But I'm not sure why I get the service discovery failed exception.
You can pair/find the device at all times manually on the phone... It does require a passcode, but I don't think that is the problem that I am having.
After three days I got it figured out thanks to some very helpful posts.
I had to replace:
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
with:
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
tmp = (BluetoothSocket) m.invoke(device, 1);
and voilà it works!
As of API 15 you can use the following method:
Try replacing your UUID with the return value of getUuids() method of BluetoothDevice class.
What worked for me was something like this:
UUID uuid = bluetoothDevice.getUuids()[0].getUuid();
BluetoothSocket socket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
The reason this works is that different devices support different UUIDs and by getting the UUIDs of the device using getUuids you are supporting all features and devices.
Another interesting new method (supported since API 14) is this: BluetoothHealth.getConnectionState. Haven't tried it but looks promising...
This was a suggested edit from an anonymous user attempting to reply to the accepted answer.
One big difference between your before and after code is the UUID you are passing. I found my answer here: http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createRfcommSocketToServiceRecord(java.util.UUID)
I had to replace:
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
with:
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
tmp = device.createRfcommSocketToServiceRecord(SPP_UUID);
and voila it works!
The original code is for a peer to peer android app. It makes no sense to use the app UUID when connecting to a simple serial bluetooth device. Thats why discovery fails.
So as it mentioned above, the point is that you need to use the UUID that the server is waiting for.
If you are connecting to a bluetooth device, such as a headset or mouse, you need to check which UUIDs the device is listening for. You can see the UUIDs like this.
UUID[] uuids = bluetoothDevice.getUuids();
And if you want to know what these UUIDs mean, see this.
This is a realy old one question but i found that using the createInsecureRfcommSocketToServiceRecord() instead of createRfcommSocketToServiceRecord() along with the getUuids() previously mentioned do the trick for me
UUID uuid = bluetoothDevice.getUuids()[0].getUuid();
BluetoothSocket socket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid);