I have a ble device that I need to regularly extract data from securely and constantly. So on startup I want to make sure to bond the device if it is not already. I have the Mac address of the device in this case.
public void startApp(){
remoteDevice = bluetoothManager.getAdapter().getRemoteDevice(MAC_AD);
if(remoteDevice.getBondState()!=12){
remoteDevice.createBond();
}
}
What ends up happening is that the bond state will alternate between unbonded and currently_bonding but not fully bond.
The strange thing is that sometimes it will work, but usually not, particularly on my google pixel. Bonding through the settings is also very inconsistent.
Is there any way to retry this or some kind of Bluetooth reset that should be done so that I can bond consistently?
I've tried calling createBond() in intervals;
I've often found that calling createBond() directly can have hit-and-miss results depending on the platform (both ends). Logically it should use the same mechanism internally, but I've tended to get better results by calling read on a simple characteristic which has bonded requirements.
It either successes - meaning your connection is bonded - and you can continue. Or it fails, which internally triggers the bonding, and then you can try again after a short delay, at which point it should now be bonded.
Related
I have some questions on the use of Bluetooth Medic, based on the following observations.
Because Bluetooth stops on one of my devices I have been looking at the BluetoothMedic to see whether it can help. I've looked at the debug messages and the source code. I get somewhat different results depending on whether I use enablePeriodicTests() or individually run runScanTest() and runTransmitterTest().
With enablePeriodicTests(), BluetoothTestJob.onStartJob() runs scan and transmitter tests every 15 minutes, apparently OK. If my beacon is transmitting, I get "Scan test succeeded" then "scan test complete" from the scan test, and if not I get "Timeout running scan test" then "scan test complete". After that the transmitter test runs and I get "Transmitter test succeeded" then "transmitter test complete" in all cases.
However I get different behaviour when I add buttons that execute the runScanTest() and runTransmitterTest() calls. In both cases the code enters the while() loops waiting for a non-null test result, and times out after 5s. Because the test results are null, the calls then return true (for the scan test) and false (for the transmitter test).
In the case of the scan test, the onScanResult() callback is never called if my beacon is not transmitting, but if the beacon is transmitting it is called 10-20 times (I see many "Scan test succeeded" messages) but only AFTER runScanTest() returns.
In the case of the transmitter test, the onStartSuccess() callback is fired once and I see a "Transmitter test succeeded" message but only AFTER the runTransmitterTest() returns.
Behaviour is the same for two devices (Android 7 and 8).
It would be good to have further documentation on these tests and how to use them.
Firstly, what do these tests do and what errors might they find?
Secondly - how should they be used? It looks like runScanTest() and runTransmitterTest() can't be called simply - do they need their own threads or something?
Finally, are they safe to use while the ranging and monitoring code is in action, or do they interfere?
The Android Beacon Library's BluetoothMedic is designed to detect symptoms of the Android bluetooth stack getting into a bad state, and then optionally cycle power to bluetooth to get out of it. The Medic looks for two OS-level error codes that come back from attempting to scan for a Bluetooth LE device or transmit a Bluetooth LE advertisement. These error codes are known to be associated with a bad state of the bluetooth stack from which recovery generally does not happen without intervention.
The simplest way to set it up is passively like this:
BluetoothMedic medic = BluetoothMedic.getInstance();
medic.enablePowerCycleOnFailures(context);
The above two lines will start the medic listening for any bluetooth errors that happen as a result of regular use of the library's functions (scanning and/or transmitting) by the enclosing app. If these are detected, it will cycle power in an attempt to recover.
This is generally safe to do, but cycling power can cause problems to other functions like classic bluetooth -- if the phone is using a bluetooth speaker when this happens, it will obviously disconnect. Bluetooth LE functions are less likely to be adversely affected by a power cycle, as the error condition in the bluetooth stack probably prevents the functions form working, anyway.
As you have seen, you can also set up the BluetoothMedic to run its own test periodically. This may be a a good idea if you app only periodically works with beacons, and you want to proactively recover from any error conditions before your app needs to use them. To set this up, call:
medic.enablePeriodicTests(context, BluetoothMedic.SCAN_TEST | BluetoothMedic.TRANSMIT_TEST);
You can also call the tests directly, but this is an advanced usage which is not the primary design. If you decide to do so, you should definitely do this on a new thread as they will otherwise block the UI thread until the test completes. This will cause problems like you describe.
If there are no BLE devices in the vicinity during the scan test, then the test "times out" and the results are inconclusive -- you don't know for sure that the bluetooth stack is in a good state. The debug line is an indication of that fact.
I'm writing an BLE application, where need to track if peripherals device is advertising or has stop.
I followed getting peripherals without duplications this and BLE Filtering behaviour of startLeScan() and I completely agree over here.
To make it feasible I kept timer which re-scan for peripherals after certain time (3 sec). But with new device available on market(with 5.0 update), some time re-scan take bit time to find peripherals.
Any suggestion or if anyone have achieved this?
Sounds like you're interested in scanning advertisements rather than connecting to devices. This is the "observer" role in Bluetooth Low Evergy, and corresponds to the "broadcaster" role more commonly known as a Beacon. (Bluetooth Core 4.1 Vol 1 Part A Section 6.2)
Typically you enable passive scanning, looking for ADV_IND packets broadcast by beacons. These may or may not contain a UUID. Alternatively, you can active scan by transmitting SCAN_REQ to which you may receive a SCAN_RSP. Many devices use different advertising content in ADV_IND and SCAN_RSP to increase the amount of information that can be broadcast - you could, for instance, fit a UUID128 into the ADV_IND followed by the Device Name in the SCAN_RSP. (Bluetooth Core 4.1 Vol 2 Part E Section 7.8.10)
Now you need to define "go away" - are you expecting the advertisements to stop or to fade away? You will get a Receive Signal Strength Indication "RSSI" with each advertisement (Bluetooth Core 4.1 Vol 2 Part E Section 7.7.65.2) - this is how iBeacon positioning works and there's plenty of support for beacon receivers in Android.
Alternatively you wait for N seconds for an advertisement that should be transmitted every T seconds where N>2T. The downside of the timed approach is that probably not receiving a beacon isn't the same as definitely receiving a weak beacon; to be sure you need N to be large and that impacts the latency between the broadcaster being switched off or moving out of range and your app detecting it.
One more thing - watch out that Advertising stops if something connects to a Peripheral (if you really are scanning for peripherals) another good reason to monitor RSSI.
First scenario: Bonded Devices
We know that if a bond is made, then most of the commercially available devices send directed advertisements in during re-connection. In situations such as this, according to BLE 4.0 specification, you cannot scan these devices on any BLE sniffer.
Second scenario: Connectable Devices
Peripheral devices are usually in this mode when they are initially in the reset phase. The central sends a connect initiator in response to an advertisement packet. This scenario offers you a lot of flexibility since you can play around with two predominant configuration options to alter connection time. These are: slavelatency on the peripheral and conninterval on the central. Now, I don't know how much effort it's going to take get it working on the Android platform, but if you use the Bluez BLE stack and a configurable peripheral such as a TI Sensor tag, then you can play around with these values.
Third scenario: Beacon devices
Since this is what your question revolves around, according to the BLE architecture, there are no parameters to play with. In this scenario, the central is just a dumb device left at the mercy of when a peripheral chooses to send it's beaconing signal.
Reference:
http://www.amazon.com/Inside-Bluetooth-Communications-Sensing-Library/dp/1608075796/ref=pd_bxgy_14_img_z
http://www.amazon.com/Bluetooth-Low-Energy-Developers-Handbook/dp/013288836X/ref=pd_bxgy_14_img_y
Edit: I forgot, have you tried setting the advertiser to non-connectable? That way you should be able to get duplicate scan results
I am dealing with a similar issue, that is, reliably track the RSSI values of multiple advertising devices over time.
It is sad, the most reliable way i found is not nice, rather dirty and battery consuming. It seems due to the number of android devices that handle BLE differently the most reliable.
I start LE scan, as soon as i get a callback i set a flag to stop and start scan again. That way you work around that DUPLICATE_PACKET filter issue since it resets whenever you start a fresh scan.
The ScanResults i dump into a sqlite db wich i shrink and evaluate once every x seconds.
It should be easy to adapt the shrinking to your use case, i.e. removing entries that are older than X, and then query for existance of a device to find out if you received a ScanResult in the last X seconds. However dont put that X value too low, as you must take into account that you still lose alot of advertisement packets on android LE scan, compared to a BLE scan on i.e. bluez..
Edit:
I can add some information i already found for speeding up the performance on Advertisement discovery. It involves modifying and compiling the bluedroid sources and root access to the device. Easiest would be building a full android yourself, i.e. Cyanogenmod.
When a LE scan is running, the bluetooth module sends the scan sesponse via HCI to the bluedroid stack. There various checks are done until it finally gets handed to the Java onScanResult(...) which is accessed via JNI.
By comparing the log of the hci data sent from the bluetooth module (can be enabled in /etc/bluetooth/bt_stack.conf) with debug output in the bluedroid stack aswell as the Java side i noticed that alot of advertisement packets are discarded, especially in some check. i dont really understand, beside that it has something to do with the bluedroid inquiry database
From the documentation of ScanResult we see that the ScanRecord includes the advertisement data plus the scan response data. So it might be that android blocks the report until it got the scan response data/ until it is clear there is no scan response data. This i could not verify, however a possibility.
As i am only interested in rapid updates on the RSSI of those packets, i simply commented that check out. It seems that way every single packet i get from the bluetooth moduly by hci is handed through to the Java side.
In file btm_ble_gap.c in function BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
comment out to_report = FALSE; in the following check starting on line 2265.
/* active scan, always wait until get scan_rsp to report the result */
if ((btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
(evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_DISCOVER_EVT)))
{
BTM_TRACE_DEBUG("btm_ble_update_inq_result scan_rsp=false, to_report=false,\
scan_type_active=%d", btm_cb.ble_ctr_cb.inq_var.scan_type);
p_i->scan_rsp = FALSE;
// to_report = FALSE; // to_report is initialized as TRUE, so we basically leave it to report it anyways.
}
else
p_i->scan_rsp = TRUE;
What´s the main difference between the WifiManager disableNetwork() and disconnect() method?
If I´m not guessing wrong, the disconnect() method makes it candidate for a reconnect when it enters inside the visibility of the wifi hotspot but disableNetwork() don't.
public boolean disableNetwork (int netId). Disable a configured network. The specified network will not be a candidate for
associating. This may result in the asynchronous delivery of state
change events.
public boolean disconnect () Disassociate from the currently active access point. This may result in the asynchronous delivery of
state change events.
I´ve a Wiko Darkmoon (Android 4.2.2) device for testing purposes and when I call disconnect() it reconnects some seconds later to the same wifi point without taking in mind higher priority networks neither the quality of the signal.
So my questions are:
What's the difference between disableNetwork() and disconnect() method?
It´s my guess right?
It´s the Wiko's implementation the right one or it´s the one misfiring?
When roaming between two wifi spots with same SSID and after calling disconnect() will it filter by SSID or MAC for the reconnect?
Thanks
disconnect() as name suggests just disconnects the device from current Wi-Fi network. If the device connects later to the same or another network is dependent on the device settings and is completely unrelated to the method call.
disableNetwork(int) will prevent automatic connection to the specified network.
I have 2 android phones phones, both connected to the same wifi, both with bluetooth.
I want some method that syncs somehow the phones and starts a function on the same time on both phones.
For example playing a song at the same time.
I already tried with bluetooth but its with lag, sometimes 0.5 secs. I want something in +- 0.01sec if possible.
Someone suggesting playing it in the future with 2-3 seconds, sending the time-stamp, but how do you sync the internal clocks of the devices then ?
Before calling that particular method, try to measure the latency between the two devices:
1.First device says Hi(store the current time)
2.Second device receives the Hi.
3.Second device says back Hi !!
4.First device receives the Hi.((storedTime - currentTime) / 2 )
Now you have the latency, send your request to second device to start your particular method and start it on first one after the latency.
Try to measure the latency 5 to 10 times to be more accurate.
you have a way to transfer data between the devices right ?
if so you can send a time-stamp which is in the future,
ex: if the present time stamp is 1421242326 you send 1421242329 or something and start the function at that time on both devices.
Basically use #Dula's suggestion (device 1 sends command to device 2 and gives a "start time" which lies in the future). Both devices then start the action at the same time (in the future).
To make sure that the devices are synchronized, you can use a server-based time sync (assuming that both devices have Internet access). To do this, each device contacts the same server (using NTP, or HTTP-based NTP, or contacts a known HTTP server, like www.google.com and uses the value in the "Date" header of the HTTP response). The "server-date" is compared to the system clock on the device, and the difference is the "time-offset from server-time". The time-offsets can be used to synchronize on the "server-time", which is then used as the time base for the actual action (playing the media, etc.).
If your WiFi router allows clients to talk to each other (many public hotspots disable this), you could implement a simple socket listener on one (or each) device and have the initiating device broadcast a message.
For more complicated things and network flexibility, I've had good success with connected sessions using AllJoin. There is a bit of a learning curve to do interesting things, but the simple stuff is pretty easy once you understand the architecture.
Use a server to provide a synchronous event to just the two clients who have decclared their mutual affinity (random as a parm and pair serializer Partner-1 or Partner-2 which they share prior to their respectve calls for the sync event).
Assume both clients on same subnet (packets from 2 events serialized on the server , arrive across the network at the 2 clients simultaneously client-side) This provides synchronous PLays by 2 , bound clients.
The event delivered by server is either a confirm to play queued selected track OR a broadcast( decoupled, more formal)
The only tricky thing is the server side algorythm implementing this:
Queue a pair of requests or error
Part1, part2 with same Random value constitute valid pair if both received before either times out.
On a valid pair schedule both to the same future event in their respective , committed responses.
OnSchedule do the actual IO for 2 paired requests. Respective packets will arrive back at respective clients at same time, each response having been subject to equal network latency
Ng if two diff carrier 4G or lte networks involved. (Oops)
This thing is possible via socket, you will send a event via socket then the other device receive that event. For learn socket io chat
maybe it's not the answer you are looking for but i think that due to the high precision you are wanting , you should look for a push technology, i advice you to take look at SignalR. It's real time technology which gives you abstraction of sending methods , it have a built-in methods like Clients.All.Broadcast that fit your needs.
You can try to use some MQTT framework to send message between two device, or into a set with more number of devices.
using the android 4.4 BLE APIs on my Nexus7, i'm able to successfully interact with a peripheral BLE device -- connect, disconnect, read, write....
if however an active connection breaks for whatever reason (in this case, the peripheral is reset), i observe the following behavior....
my peripheral (by design) begins advertising after any active connection is terminated (for whatever reason); i can see this via my bluetooth packet sniffer....
i receive the onConnectionStateChanged callback as expected in my android app, at which point i invoke close() on my active BluetoothGatt instance; this is the same procedure i follow during a "normal" disconnect initiated from the client...
shortly after this, the android BLE stack tries to re-connect to the same peripheral; through the packet sniffer i can see the BLE connection request going out over the air...
my app, however, did not initiate this re-connection; indeed, i see no information from any bluetooth log suggesting this even happened!!!!
is there some "mode" in the BLE stack where it attempts to re-establish busted connections automatically???
thanks....
This happens on various Android phones whether the autoConnect flag is set to false or true.
Couldn't yet find a complete solution, it seems as the android BLE stack is spontaneously re-initiating the connection once it is getting the advertising signal again, just ignoring that it was the app that disconnected on purpose...
A partial solution may involve not using the BluetoothGatt.connect() method as explained here:
https://stackoverflow.com/a/23749770/4144487
So, a sample connect method can look like:
void connect(Context context) {
if (mGatt != null) {
mGatt.close();
}
mGatt = mDevice.connectGatt(context, false, callback);
}
To explain the importance of this issue, when it happens the peripheral thinks it is connected and my "real" app can't find it any more. At some phones like Galaxy S3 and Redmi note 3 I found that closing the bluetooth switch from the notification bar is "releasing" the peripheral and allowing me to discover the device. At others like Nexus 5x only a phone reboot will do the trick.
I've observed this happening if you use autoConnect=true when calling BluetoothGatt#connectGatt(). Generally I've found that it is best to use autoConnect=false, but with some devices you simply cannot connect unless you use true, so I usually do both. I try false first and if that fails then use true and then the behavior you're describing is something you simply have to work around.