How to "ping" with Android BLE - android

Is there any simple way to check if an existing BluetoothDevice object is still reachable without performing a new scan?
I am writing an app that scans for devices and goes through connecting to each one at a time to populate a device list with some information about each device, which I acquire while connected to the device. Every now and again, I would like to go through my device list and remove any devices that are no longer active/in range. What is the best way to do this?

You could try to connect to the devices to find out if they are still around, but keep in mind, that devices will change their mac address from time to time.
I would suggest to use scanning to find out if the devices are still around. Also you may want to add an identifier into the advertisement packages, so you don't need to relay on the mac address.

Related

How to work around Android rotating the BLE Mac Address after every connection?

I'm working on a project where a central device connects to peripherals advertising a specific GATT service. The central device exchanges some information with the phone after which the connection is no longer needed and the device disconnects.
The problem that I'm running into is that the phone seems to change its MAC address after every new connection. So basically, every time I connect to a device it looks like a new device appears. So my central node tries to connect to the new service again. This is very annoying since I was thinking of using the MAC address to know that I had already connected to the device and did not need to do the information exchange again. Note that I know that the MAC address rotates every 30 minutes anyways and that's something I'm willing to deal with, connecting once every 30 minutes is fine, but the rotation on connection causes my device to chain connect to the phone that always appear like a new device.
A few ideas I have thought of to work around this:
Obtain the new MAC address from the phone and share it with the central device. That has 2 issues:
MAC Address is not accessible with the Android APIs except using sketchy reflection.
It would only work if a single central device is in Range, since only the last node would know the new MAC address to avoid.
Advertise service Data with a random ID that I would manually rotate every 30 minutes. This data could be in the same advertisement packet. That allows me to ID the device without compromising privacy.
It however might be very hard to implement on iOS that has very restrictive background advertisement APIs. iOS doesn't actually appear to have the same behavior though so it might be possible to implement a completely different method for iOS.
Disabling this "rotate MAC on connection" feature doesn't seem possible.
How can I work around this issue?
If you Bluetooth pair the devices, then the Android device will send over its IRK (Identity Resolving Key). With this you will be able to derive if a given Bluetooth Device Address was generated by the particular IRK or not. That way you can identify an Android device. It works the same if you replace Android with iOS.
See your Bluetooth stack's documentation how to deal with IRKs.

HM-10 as BLE Listener: setting up a brief connection from it

I need to estabilish a brief communication between a BLE master and a BLE peripherical device.
Until I have to use the mobile phone I have no problems, since I select the bluetooth device from Android, I can connect to it and then I can receive data simply writing them to HM-10.
BUT, this approach is battery expensive, since the BLE scanning is more battery expensive than the BLE advertising (right?). So I want that the mobile becames an advertisor and the HM-10 takes the ROLE of Slave.
BUT, I still don't understand if it is possible to connect to other devices: I tried AT+CONN and it always fails (AT+CONF). Is there any way to send brief data from the HM-10 to the advertisor, even without connecting?
Even my firmware looks slightly different from the readme! For example,AT+LN is present in the documentation but it appears to not exist. Does a better version of the firmware for this device exist, or, are sources available somewhere? I installed the HM-Soft V705 (lastest).
Thanks
UPDATE 1:
#ChrisStratton Ok, I have some intresting news: I was already following your idea (phone advertise sometimes, while HM-10 always scan and tries to connect to the service if it sees it, then HM-10 send some data, phone answer). I managed to make the phone visible from HM-10 (don't ask me how!). I am using the BLE Tool Android app to test everything. Now, the central problem now is that HM-10 won't connect to the android service even if the advertisor is connectable (see attached images).
I am sospicious that the AT+CO (that I discovered is a kind a replacement of AT+LN, but I am not sure) can help, but i don't know how.

Android save BLE device to reconnect after app close

I'm developing an android BLE app in which i try to establish a stable Connection between the app and a BLE device.
To achieve this i want my app to keep the BLE device data in shared preferences or somewhere.
After app close, i'd like my app to retrive this data and attemp a connection without scan for devices.
I prefer to avoid scanning every time becouse scan gives me a lot of problems and it takes time.
How can do it? Is there a way to save BLE data?
You need to store the Bluetooth Device Address (AB:CD:EF:01:02:03) of the device in for example shared preferences or in a sqlite db. Then use https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getRemoteDevice(java.lang.String) when you later restart the app to retrieve a BluetoothDevice object. Once you have the BluetoothDevice object you can use the connectGatt method as usual.
There are some undocumented things you need to keep in mind however. Due to some horrible design flaws in Android's BLE API there is no way to tell it if you mean the given address is a Public Address or a Random Address. (You can read more about different address types at https://devzone.nordicsemi.com/question/43670/how-to-distinguish-between-random-and-public-gap-addresses/). The getRemoteDevice method should take an additional parameter "random address/public address" but it doesn't. Without the correct address type, the Bluetooth controller cannot connect to the device.
Android's BLE stack has some internal heuristics to "guess" if the address is public or random, but unfortunately that differs between Android versions and also if you use autoConnect=true or false. However if you have bonded the device (https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createBond()) then it will store in its internal DB whether the given address is public or random. If the peripheral you want to connect to uses a random resolvable address it can handle that as well if you use bonding. Therefore I strongly suggest to use bonding.
If you don't use bonding you will need to scan before you connect to the device, since when you start a scan and a device is detected, Android's BLE stack will temporarily (until next restart of Bluetooth) remember the address type for an address.
I will continue on Emil's answer.
Thanks #Emil for the 'big picture'.
Google API is flawed and you can't use getRemoteDevice() because it only understand 48bit address and do not know about all BLE address types.
You can't use Bonding if the device is dumb (anyone would be able to bond to it).
So your only solution is a Bluetooth scan.
However, since Android6 (Marshmallow) the user has to give location permission to apps using Bluetooth scanning. If you don't permit, it won't work.
So if you buy a Bluetooth thermometer (or heart-rate monitor or whatever), you have to permit the app to access location of your phone (or tablet).
That's absurd!
#Emil call it a 'Google flaw'. You may also call it a 'Google machination'.
If I was a thermometer designer, I would add a push-button to accept bonding. It seems ridiculous because the button will only be used once.
[1]: https://www.polidea.com/blog/a-curious-relationship-android-ble-and-location/

Android Development: Discovery of other devices using my app over Bluetooth

I am developing an android app where users must be able to see other users nearby them and send a message to that user specifically. I was hoping Bluetooth would be a good, low-energy solution to this. My trouble is in identifying nearby Bluetooth devices only if they are using this app, and ignoring all others, such as portable speakers and whatnot. Could anybody maybe point me in the right direction on this one?
As far as limiting the discovery, this seems not possible at this point in time. The only way I can think of where this would really be possible is if their device name had a particular string in it that you used to filter, but this isn't really something I would look into as people probably won't go as far as changing the name of their device just for an app.
You can use the following to change the device name, I would recommend getting permission & maybe appending the device's previous name onto whatever string you want to look for
BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();
mBtAdapter.setName("");
I don't think if you are in the middle of a connection it would end it, as a bluetooth connection is made using the devices bluetooth MAC address, not the devices name

Manually pairing Bluetooth Decives in Android?

I was reading this
http://developer.android.com/guide/topics/wireless/bluetooth.html#QueryingPairedDevices
which is allot of help on how to pair,connect to a bluetooth device.
I have a situation where I have several BT devices that are in Non-Discover mode always. I know the MAC and the PIN of these devices. IS there a way in Android Dev to manually add devices to the PAIRED list so i can just use the connect as a client.
I understand this maual is written allot for V3. i think i will need to do this on 2.0 ; 2.1- has anybody done this before?
Basically these devices I want to connect to are power saving modules I used pre built BT modules to monitor daylight, another one humidity, etc.. every 3hrs or when interrupted and runs of a single battery for months. So turning off divcory on server saves immense power and prevents other people trying to connect and waste battery.
Not sure what you mean by "manually": Do you mean "manually" as in GUI/user interaction, or "manually" as "I do it in my own application code"?
Some suggestions though:
If you can make your BT devices discoverable at all, you could do it this way:
Make your BT device discoverable
Let Android search for and find the device and then initiate a connection
Android will ask for the PIN for pairing with the device; enter the PIN.
Once pairing was successful, Android stores the pairing information for future use, so that you can
Make your BT device invisible again.
From then on your app should be able to connect to the BT device at any time without further pairing operations.
If the said is not an option for you, maybe you want to go another way:
In current Android versions there are different API routines implemented which are neither documented nor exposed in the normal SDK. A hack kind of solution may be to use some of these "hidden" ("#hide"...) APIs, either via reflection or via modification of your SDK installation.
But be aware that this is always a hack and it may work on a specific device with a specific version of Android and is likely to break your app on another device and/or any other Android version.
Having said that, here comes some reference:
Example of how to access "hidden" bluetooth API.
Then, have a look at the source code for android.bluetooth.BluetoothDevice, e.g. here.
In there, public boolean createBond(){...} may do what you want.

Categories

Resources