My application doesn't use beacons (at least not in the common meaning). The use case is to continuously background scan for BLE peripherals matching a specific format, then connect to those peripherals and transmit/receive data and disconnect (possibly doing this more than once).
The stability and reliability of Bluetooth LE on Android leaves something to be desired, especially if supporting earlier API versions (18+), as I am. AltBeacon seems to be a seasoned library that handles a lot of the weird edge cases and intricacies in Android Bluetooth LE management (at least on the scanning side). I'd like to leverage this library to scan and identify my peripherals and then connect to them on my own. Does anyone know how I might be able to achieve this?
While the Android Beacon Library really is not designed to scan for bluetooth services, there are certain cases where it can be convenient for that purpose. Be forewarned, however, that doing this goes against the grain of its design, and forces you to do a few pretty ugly hacks. If such hacks make your eyes bleed, then read no further! For those who can stand it, here's what you'd need to do:
Set up a beacon parser that will look for a GATT Service UUID. You must match on a few bytes in the service UUID, and the library's matchers are only designed to match a few bytes at a time. So if you have a GATT Service UUID of 00010203-0405-0607-0809-0a0b0c0d0e0f, you should take the first three bytes: 00,01,02 and use them as the matching expression. Because the matching expression has a different endianness, you have to reverse the order of the bytes to be 02,01,00. So you end up with code like this:
BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("m:0-2=020100,i:0-15l,p:15-15"));
Start ranging based on a region that matches your full GATT Service UUID. (Again, you must replace the UUID with that of your service.):
Region gattServiceRegion = new Region("gattServiceRegion",
Identifier.parse("00010203-0405-0607-0809-0a0b0c0d0e0f"), null, null);
beaconManager.setRangeNotifier(this);
beaconManager.startRangingBeaconsInRegion(region);
Now the library will make a callback to your class' didRangeBeaconsInRegion method each time it sees an advertisement for that GATT Service UUID. So you know it is nearby, and you can get all of the power saving, background launching and other benefits of the library. The problem now is that the library doesn't expose any reference to the raw BluetoothDevice object needed to call connectGatt(...).
So unless you modify the library source code you still have to use the raw scanning APIs once you know the beacon is around just to get this reference. You have to decide if using the Library is worth all this trouble, given that you have to use the raw scanning APIs to get the BluetoothDevice to make a connection, anyway.
Related
I've seen a lot of discussions on battery for altbeacon, specially if beacons are inside a region for a long time. This post was actually very clarifying.
I am currently working in a solution that requires a good sensibility (which I define as being a small detection time for a new beacon in a region).
As some beacons may be anonymous (which I define as presenting unexpected MAC addresses but share a same matching byte sequence) to the scanner in this particular solution, I would like to achieve good sensibility to new beacons but also a balanced battery impact to the user.
What concerns me is if a first beacon is found and the region triggers based on the matching sequence, how could I get a notification once another beacon approaches (or leaves) ?
A guess I was going to try was to keep monitoring for a generic matching sequence and once a beacon is found for that general sequence, range it to get its address and them create a particular region for the mac I've taken. The only problem with this approach was how could I prevent the first beacon to keep triggering the generic region?
And just out of curiosity. Is the ScanFilter class related to those hardware filters introduced on android 5?
Thank you,
If you need to quickly find new beacons with the same byte patterns as ones that already exist in the vicinity, you really have no choice but to keep ranging.
In such a situation, there is no distinction between ranging and monitoring in terms of battery consumption. Both will require constant Bluetooth scans and decoding of all beacons in the vicinity. Scan filters (yes, the hardware filters introduced in Android 5,) will not help because you expect the byte patterns to be the same. There is no such thing as a packet "does not match" scan filter that could be used to find only new MAC addresses.
You may need to accept the battery drain of constant scans and just try to limit how long they last, if your use case allows. Short scans of 30 minutes or less might be acceptable.
You could possibly save some battery by writing your own BLE scanning parsing code tailored to this use case. You could first look for unique MAC addresses, and only do further processing and parsing if the MAC address has never been seen before. This will not reduce battery usage from the constant scan, but it would cut down on battery usage from CPU expended on parsing packets. This might save 10-30% depending on the number of beacons in the vicinity.
Bottom line: you are right to be concerned about battery usage with this use case.
I want to transmit iBeacon data packet from android phone, with data flag.
Data Flag (0x01) is Bluetooth GAP specification that represents beacon's capability.
My situation:
Currently, I'm trying to advertise using BluetoothLeAdvertiser. But it doesn't works as I thought. I found that, I can only advertise "Manufacturer specific data".
BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = manager.getAdapter();
mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
// Settings here
mBluetoothLeAdvertiser.startAdvertising(settings, getAdvertiseData(), mAdvertiseCallback);
My current result:
What I want:
Common iBeacon data packet(Image below) has data flag, Type 0x01. And I want to add this flag to my iBeacon advertise packet.
That means, I want add Raw data "0x020106" to head part of the packet.
How can I archive this?
Etc:
I have already read about question below, but it doesn't help for my problem.
Can an Android device act as an iBeacon?
Also, I already have read that android ble api doesn't support Data flag.
But the comment was in 2015, is there any hopeful changes now?
https://github.com/AltBeacon/android-beacon-library/issues/141
Unfortunately, this is not currently allowed by the Android BLE APIs, so the library cannot this.
Any help will be appreciated. Thank you.
Unfortunately, Android's Java BLE APIs expose no way of doing this. I researched this topic to answer the Android Beacon Library Issue you referenced. The Java APIs only let you advertise either service data or manufacturer data. They are simply not flexible enough to let you specify any other advertising PDUs. This has not changed as of May 2016.
You might be able to do what you want by dropping down to a lower level and talking to C BlueDroid APIs. But doing this would require a rooted device and perhaps installing a custom Android OS image to give you access.
I'm attempting to transmit as a beacon an Android phone using the altbeacon library as described here. I am trying to set some parameters using the following methods:
setServiceUuid(0xfeaa)
setBluetoothAddress("31:14:15:92:65:35")
setBluetoothName("MyBeacon")
When the beacon is interpreted on another Android device in the RangeNotifier listener method, didRangeBeaconsInRegion, the beacon doesn't have these parameters set. (eg. getServiceUuid is -1 and the BT address and name are each null).
I'm using the following beacon layout in the parser for the transmitting application and in the scanning application:
m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
I don't know what this means though; I wonder if I need to change it.
Anyone have an idea how to make the bluetooth address, name etc. be accessible in the beacon that is scanned on the receiving device?
Some fields in the Beacon class are only used when detecting beacons and do not affect transmissions. You have found three of these exact fields. Here is an explanation of each and why they work this way:
BluetoothAddress: this is a fixed six byte unique address built into the Bluetooth chip on your phone. When sending packets (beacon advertisements or otherwise), the chip always uses the same address. You cannot change it. This is by just the way Bluetooth works.
BluetoothName: this is the friendly name of your phone visible to other Bluetooth scanners. Changing this name affects not just beacon transmissions but all Bluetooth operations on the phone. For this reason, the library's BeaconTransmitter does not change this name. You can do so youself, however, by calling the setName method on Android's BluetoothAdapter class. See here.
ServiceUUID: This field applies only to certain beacon formats such as Eddystone, which are based on 16-bit GATT Service UUIDs. For other beacon formats (AltBeacon, iBeacon), this value is -1 as you have seen. The ServiceUUID is actually defined in the BeaconParser layout expression. In the Beacon class you can read it, but writing to it has no effect. You generally do not need to worry about this field, and certainly not for the AltBeacon layout shown in the question, because it is not used for that format.
We're trying to emulate a beacon on a Android device and would like to include some 50 bytes of application data in payload? We found that with AltBeacon format this is not possible? How can it be done with help of AltBeacon lib for Android?
Moreover, what are primary and secondary beacon advertisements?
What is role of GattBeacon in this context and when and how should it be used?
There are two basic types of BLE beacon advertisements:
Manufacturer advertisements (iBeacon, AltBeacon, Gimbal)
GATT Service Advertisements (Eddystone, UriBeacon, GattBeacon)
They differ mainly by the bluetoorh PDU type, but in both cases the number of bytes that can be transmitted are similarly limited. It is 23 bytes for manufacturer advertisements (not counting the two byte manufacturer code).
With Bluetooth 4.x, you just won't get close to 50 bytes in a single packet. Bluetooth 5.0 is expected to increase this at some point in the future.
None of the beacon layouts let you go beyond this limit. GattBeacon is merely a generic example layout of a beacon based on GATT Service advertisements, and is not meant for practical use.
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;