Have you ever seen the apple watch unlock a Mac? The idea is amazing, but I don't want a smart watch because I already have a phone which has similar capabilities AFAIK.
Also, I moved from OSX to Linux recently :)
I don't know how the Apple watch manages to unlock the Mac. But I know what would be desirable from a user experience point of view:
Needs to unlock quicker than I type my password
Should work in absence of wifi/4G
Should be power efficient
RFID
RFID would be nice, but no laptops that I know embed RFID readers.
Bluetooth based proximity detection
The challenge with classic Bluetooth is the requirement to constantly scan for near devices to measure the signal strenght (RSSI) from which we can infer the proximity.
Unfortunately discovery hops and listens 40 channels. And anyway the phones stop broadcasting when screen is off for a while. This is not good enough. I know because I tried:
import collection.JavaConverters._
import tinyb._
object Listener extends App {
var running = true
val BT_ADDR = sys.env.getOrElse("BT_ADDR", "XX:XX:XX:XX:XX:XX")
val BT_RSSI_DBM_THRESHOLD = Integer.parseInt(sys.env.getOrElse("BT_RSSI_DBM_THRESHOLD", "-65")).toShort
val manager = BluetoothManager.getBluetoothManager
val lock = new Object
while (true) {
manager.getAdapters.forEach(a => {
a.setRssiDiscoveryFilter(BT_RSSI_DBM_THRESHOLD)
a.removeDevices()
})
System.err.println("scanning for " + BT_ADDR + " at minimum " + BT_RSSI_DBM_THRESHOLD + " dBm RSSI...")
manager.startNearbyDiscovery(
(device: BluetoothDevice) => {
if (BT_ADDR.equals(device.getAddress)) {
onProximity(device)
manager.stopNearbyDiscovery()
lock.synchronized(lock.notify())
}
else println(device.getName)
}
, 1000
, false
)
lock.synchronized(lock.wait())
}
}
I was looking at BTLE (Bluetooth Low Energy), and I'm having difficulty to understand the following:
Is there a way to establish from Linux a single low energy bluetooth connection to the Android phone which we can leave dormant all the time, and use it to wake the phone up and make it transmit some packets (so we can measure its RSSI power and infer proximity) on demand, only when strictly needed.
I.e. we'd limit transmissions to only these rare occasions:
Check when the user is away if we detect inactive mouse & keyboard for 1 minute,
Check if the user is near enough when GDM is active
No BT activity whatsoever otherwise
This approach is quick, energy efficient, and does not require network protocol, only some rare BT transmission.
But is this possible with Bluetooth LE? Any pointers to examples?
Yes this should be possible with Bluetooth Low Energy (with some caveats) as follows:-
You need a BlueZ script/C program to constantly scan for your Android device.
You need your phone's Bluetooth to always be turned on.
You will need to pair at least once so that your Linux machine recognizes the changeable Bluetooth address of your Android device (see referenced links).
The BlueZ script program should be written so that as soon as your Linux system goes to standby, the program is launched as a daemon or background process that just starts scanning for Android devices and read their RSSI values. If your device is found and the RSSI value indicates that it is within range, this process will signal the Linux OS to wake up.
The caveats:-
BLE is not ideal for positioning/locationing; you can probably detect
if you're a few metres away but it would be challenging to get an
accuracy of a few centimeters.
Your BlueZ script needs to be
constantly running as a daemon or background process, so if it is
somehow killed or is inactive when the device goes to sleep, this
will not work.
Bluetooth on your phone should be always on, which
shouldn't have a big impact on the battery life but is also not
recommended.
Some resources for you:-
Running Bluetooth applications in the background in Linux
Bluetooth Low Energy: A Primer
Getting Started with Bluetooth Low Energy
Introduction to BLE
Bluetooth LE Signal Strength in Linux
Should One Create a Bond with a Bluetooth LE Device
How to Detect Whether System is Going to Standby in Linux
Android Bluetooth Low Energy Overview
Using Bluetooth Low Energy in Linux Command Line
It will not be a straight forward process and you'll probably have to try and fail along the way, but it will be a learning experience and you should be able to achieve what you want in the end.
I hope this helps.
Related
Google introduced a set of limitations in Android 8 or 9 regarding Wi-Fi scanning frequency. Apps are restricted in how frequently they're able to scan for Wi-Fi connections, including P2P Wi-Fi peers. What is the situation with Wi-Fi Aware? Does it have the same limitation? Is it easier to bypass it?
This answer is as per the latest comments by OP.
One way to keep track of the RSSI of the network is to register for the intent RSSI_CHANGED_ACTION using a BroadcastReceiver and then extract the raw RSSI values from the Intent's extra values which are stored with the key Wi-FiManager.EXTRA_NEW_RSSI and obtain the threshold levels(usually the workable values) using calculateSignalLevel(). Some approximate code:
} else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
// Default to -200 as its below WifiManager.MIN_RSSI.
int rawRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
int rssiLevel = mWifiManager.calculateSignalLevel(rawRssi);
}
Also, to answer the previous question as to whether Wi-Fi aware is restricted by the same scan restrictions, the answer is 'no', not because it has a waiver vis-a-vis Wi-Fi-Direct but because it operates differently from a Wi-Fi-Direct connection. For a Wi-Fi Direct connection, one needs to make a request() to the WifiManager for initiating a scan and it is these scans that are throttled, with the duration of throttling varying based on whether the app is in foreground/background. This throttling can of course be overridden from the Developer Settings page.
Wi-Fi-Aware works with a different paradigm. If this is regarding the usage of ranging, then one can leverage Wi-Fi-Aware technology between two devices as follows:
Check whether ranging is supported using Wi-Fi-RTTI apis using context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);
Check whether Wi-Fi RTT is available by registering for the intent WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED and on its receipt, check for whether Wi-Fi RTT is available.
Create a ranging request
Start ranging
Extract rssi from a successful ranging result.
One thing to note is that the requests for ranging are limited to 20 from each UID as per this code from the framework.
static final int MAX_QUEUED_PER_UID = 20;
Note that if you're running as a regular application, your app would have its own UID.
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;
I a trying to understand and modify the BLE sample von Android.com, now I can discover my sample BLE Device (HTC Fetch) and now I want to understand all that GATT and BLE stuff.
What are Characteristics and what are Profile and what are Serivces and what do they mean in the Bluetooth Low Energy World? I used HTC Dev and found a Service and a Characteristics UUID.
https://www.htcdev.com/devcenter/opensense-sdk/bluetooth-smart/htc-fetch/
But I guess what I need is the Find Me Profile, cause for the first steps I only want to get the Find Me react to a Button click.
https://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
How to implement this in my App?
When I understand everything I try Power and Proximity (reading RSSI and compare with defined range).
Can some one help me understanding Bluetooth LE?
Here's a related post
How to use the profile of PROXIMITY PROFILE,IMMEDIATE ALERT SERVICE and Find Me Profile in android 4.3 BLE?
Basically you can approximate a proximity level using tx+power - rssi or distance roughly with
d = (rssi-A)/-20 (where A = rssi at one meter) or simply use rssi mapping out ranges to display You could also initially base it on just the connection range and skip rssi.
As for the FindMe, simply write the low or high alert values to make it sound when you press a button in your app. For pressing a button on the device use the UUIDs shown in the documentation.
sample code for that device is forthcoming
I am working on using the BT 4.0 API that Motorola has provided with the RAZR. In one of their documents it states to use the Android API to pair before connecting and using their framework. Per their instructions I have been pairing with OS Bluetooth settings application, but it never prompts me for a key. It will pair but doesn't appear to bond, and this is critical for me.
My question is, when they say "using the Android API" is this referring to simply using the OS Bluetooth utility to pair before hand (like I have been doing), or is there some way to do it with code in my application. They reference the "createBond()" function which, to my knowledge, is not an accessible function (at least not without some squirrely libraries or reflection).
Any advice is greatly appreciated, especially anyone who has used the API successfully, if they could give an account of their process. I'm just looking for some clarity at this point :)
Lloyd,
You are correct, follow the instructions in the link you posted.
Outside of coding, when they say use the standard android api for "non-le" operations, they mean go ahead and pair the ble device the same way you would any bluetooth classic devices inside android settings -> wireless & network -> bluetooth -> scan for devices.
If the device you are using is a motorola le compatible device the ble device will be paired but not connected.
Now, in the code, you can detect this paired device through the same method of
BluetoothAdapter.getDefaultAdapter().getBondedDevices()
To double check if your Android Phone is LE compatible, run this code:
public static boolean checkBLESupport() {
boolean deviceSupportsLE;
try {
#SuppressWarnings({ "unused", "rawtypes" })
Class object = Class.forName("android.server.BluetoothGattService");
deviceSupportsLE = true;
} catch (Exception e) {
deviceSupportsLE = false;
}
return deviceSupportsLE;
}
And to double check if the bluetooth device you paired is LE, when you are looping through the bonded devices.
Check the device with this code.
if (device.getBluetoothClass() == null) {
Log.i(TAG, "This device is BLE compatible");
b = true;
} else {
Log.i(TAG, "This device is not BLE");
b = false;
}
Now for establishing connection from your LE compatible phone to your LE compatible bluetooth device, follow the Gatt service instructions under the link you posted. http://developer.motorola.com/docs/bluetooth-low-energy-api/
Take note that under this example it is connecting to a bluetooth low energy heart rate monitor.
If you are not trying to connect to the heart rate monitor with LE heart rate profile, here is a link to another Motorola document that details creating your own LE Profile to use with the GATT framework. http://developer.motorola.com/docs/bluetooth-low-energy-gatt-framework-api/
If the instructions are not clear enough at any point in either of these documents, motorola offers sample android applications using the frameworks in those documents.
I guess motorola stack has BLE support. But what i feel is that it does not pair with the devices that require bonding though It does work some sensors. I have tried with a proximity sensor that require bonding. It never gets paired though the devices is discovered with Razr which even does not with S3.
There's a helpful video here.
Late to the game, but can confirm -
If your BLE Peripheral requires bonding, Moto X - and some other older Motorola devices - MUST be paired via Bluetooth Settings prior to programmatic connection via the Android GATT interface.
If you bond via the createBond method, or reading of an encrypted characteristic, your connection will be dropped typically in under 60 seconds, despite DDMS logs that show a good bond may be established.
I've got a problem. I'm developing an android application that scans for wireless accesspoints/routers. I've been testing a couple of devices and I'm getting scan rates of 2, 1, 0.5, 0.1 etc. scans per second.
My goal is to reach 10 scans per second because a router can send beacons 10 times a second. And we need this for our application.
Is there away to make this possible? Perhapse hack a rom and replace the wifi drivers? I've been looking in to this but I can't find anything about this frequentie inside the driver.
The driver used is BCM4329 driver, I can't find any datasheets of the BCM4329 so it's kinda hard to figure this out.
Thanks in advance.
flitjes
I'm not familiar with driver development but I know it's one of the hardest thing in computer science so unless you have good knowledge in linux kernel development I would forget about it.
Moreover, you still need to scan the 12 Wi-fi channels to be sure that you are detecting all access points. An access point broadcasts a beacon every 100ms * 12 channels = 1.2 seconds. Spending less time than that and you risk missing access points.
You don't need to change anything in the device driver, Android makes it available to you to scan for access points. See the documentation.
Although requesting that many scans will probably not be very good for the battery life and the responsiveness of your app...
Your assumption that beacon rate is 10 per second is incorrect. This is really an AP configuration parameter, although 10 per sec is default in most. Besides that, APs do not send beacons simultaneously, if this happens, it's called a collision and a back-off algorithm is used for retransmission. In addition, even scanning 10 times per second doesn't make it certain for you to capture all beacons, like was pointed out in the previous answers.
if u use 4339 driver, you could not set the scan rate in driver or android api which is fixed in 4339 firmware, scan is about all channels && time u spend on each channel, according to the 80211 spec, which is part of mac && phy. in this case u just need to get the beacon, so u should use passive scan and use fixed channel && MaxChannelTime u want.
u have to ask broadcom for speical fw to figure out your problem,
IEEE
Std 802.11-2012 page 978
10.1.4.2 Passive scanning
If the ScanType parameter indicates a passive scan, the STA shall listen to each channel scanned for no
longer than a maximum duration defined by the MaxChannelTime parameter.