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.
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.
In the application I am looking forward Bluetooth in Beacon is very good option as I want to collect PH from different sources to the application so I can't pair my android device with all the BLE devices at a time as it will be around 20-30.
But I can see that if there is Beacon then Android can scan all of them and also get the RSSI of all devices without being paired with them.
So is it possible that we add few other parameter for example PH, Temperature, Humidity and 3-4 other parameters so Beacon is going to broadcast all these parameter along with RSSI and in Android app I can collect all the information?
I am not sure if this is feasible solution or not and if it is then how to achieve this in beacon?
Bluetooth beacons generally rely upon advertisement packets to send data, which are limited in the number of bytes available. For manufacturer advertisements, you basically have 24 usable bytes to work with, although you need to reserve some of these as a flag to indicate it is your beacon format, and not somebody else's beacon format.
You can look at the AltBeacon spec as an example. This format uses two bytes to identify itself (the "beacon code"), 20 bytes of beacon identifiers, one byte of data and one byte for reference RSSI. You probably still want a unique identifier for each beacon so you know which beacon sent you the information. But you might be able to cut this down to four bytes for your purposes, which would allow you to have 2^32 different beacons sending this information.
The Android Beacon Library lets you both transmit and receive beacons using arbitrary formats you can define using the BeaconParser class. A beacon format that uses a four byte identifier, two bytes each for PH, Temperature and Humidity data fields, and two bytes each for five other data fields might look like this:
m:2-3=abcd,i:4-7,d:8-9,d:10-11,d:12-13,d:14-15,d:16-17,d:18-19,d:20-21,d:22-23,p:24-24
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.
I am working on a project for configuring beacons. A certain amount of time after being powered on, a beacon becomes unconfigurable until it is power-cycled. In order to show a list of the configurable beacons, I am looking at certain characteristics (Bluetooth device name, certain manufacturer data in the advertising packet). I also need to know if it is "connectable", i. e. if the PDU Type in the BLE advertising packet for the device indicates that it is connectable. I've searched the Android Bluetooth classes high and low, both in Android 4.X and 5.X and haven't been able to find anything that will tell me this information.
I realize that one way to determine the beacon connectability is to connect up to it, e. g.: device.connectGatt(...). However, I've seen it take over two minutes sometimes before a callback to onConnectionStateChange comes back with STATE_DISCONNECTED. Also, there may be many of these beacons in an environment, and connecting up to every single one that might be configurable would be inefficient.
The iOS equivalent of this attribute can be found in the advertisementData dictionary under the key CBAdvertisementDataIsConnectable in the CBCentralManagerDelegate callback method centralManager:didDiscoverPeripheral:advertisementData:RSSI.
So, the question is: is there a way on Android to determine whether or not a BLE device is "connectable" from advertising data or scan result or ... ?
UPDATE: AS of the finalized APIs in the Android O SDK, the ScanResult class (itself added as of Android 5.0) now has the isConnectable() method. Detecting connectable advertisements is possible only on Android 8.0+. See here for more info: https://developer.android.com/reference/android/bluetooth/le/ScanResult.html#isConnectable()
Prior to Android 8.0, unfortunately it is not possible.
A connectable advertisement is determined by the PDU Header byte 0. You can see this in the example structure below:
d6 be 89 8e # Access address for advertising data (this is always the same fixed value)
40 # Advertising Channel PDU Header byte 0. Contains: (type = 0), (tx add = 1), (rx add = 0)
24 # Advertising Channel PDU Header byte 1. Contains: (length = total bytes of the advertising payload + 6 bytes for the BLE mac address.)
05 a2 17 6e 3d 71 # Bluetooth Mac
The problem is on devices prior to Anroid 8.0, the Android scanning APIs give you no access to these headers. You get exactly three fields in the callback from Android 4.x:
onLeScan(BluetoothDevice device, rssi, byte[] scan data)
The scan data byte array starts after the header bytes mentioned above. And from what I can see of the BluetoothDevice definition, none of the fields or methods tell you if it is a connectable advertisement -- the class is just a container for the bluetooth mac address with methods to exercise functions on the bluetooth stack. And there are no methods in IBluetooth.aidl which is the private interface to the bluetooth stack (and what BluetoothDevice calls to get its info) that can get this flag.
It appears that this information is not passed up to the Java layer from the BlueDroid stack prior to Android 8.0.
It should be possible since Nordic's nRF Master Control Panel does this.
After some digging I think I know how it does this. I'm not sure it's the right way to do it though.
I tried using the LE Advertiser and setting the device as connectable. In the Nordic app, a device is set as connectable depending on the bytes found at scanResult.getFlags().
I found that this code works for my devices:
int flags = scanResult.getScanRecord().getAdvertiseFlags();
if ((flags & 2) == 2) {
//connectable
}
Recently I got a iBeacon device with the intention of creating Android Apps than can recognize it and use it. I'm new using bluetooth in Android Apps and there many things than I still don't know. Looking in the Internet and in this forum I found recommendations to use the Radius Networks' Android IBeacon Library but, alas, now it's no longer available:
https://github.com/RadiusNetworks/android-ibeacon-service
So I started by using the code shown in Android Developers' guide about Bluetooth Low Energy:
https://developer.android.com/guide/topics/connectivity/bluetooth-le.html
Using this code I can detect the device, even connect to it, but I don't know how to get the Proximity Uuid and the Major and Minor values: the app shows a lot of Uuids from services and characteristics of the device, but none is the Proximity Uuid of the device.
Anyone could tell me how to get that data using the Android Bluetooth LE API, or help me to get the Radius Networks' Android iBeacon library for Eclipse and a guide to use it or sample showing how to use it?
Thank you.
EDIT/UPDATE:
It gets better.. AltBeacon !
Check the AltBeacon specifications
AltBeacon brings greater transparency to what a beacon transmits and
how that data can be used by Android, Windows and other devices.
Why the Android iBeacon Library by RadiusNetworks is no longer available:
Vendors have started complying with guidelines set by Apple and have,
as a result, been forced to ‘scrub’ their products of any references
or connection between Android devices and their detection of iBeacon
protocols.
Read more:
Apple cracks down on iBeacon for Android
I think the best bet seems to be from somebody who has been using it, already has it, can share it with you, as from previous commits, you may not get every component - library, sample, service
Also: A note from the CEO for Android iBeacon Lib, RadiusNetworks
Now, coming to Proximity UUID and major, minors:
I have not found a direct way to get it, in terms of a parameter, though you can have a look at read major, minor, uuid of beacons in android and SensorTag using iBeacon Technology. In the latter, there is an indication of major, minor, uuid after iBeacon Service, however TI instruments might be the restriction.
In android, as an identifier.. you can recover the device addressby device.getAddress() of the beacon/for each BluetoothDevice device;.
The following two are totally different things, although both are called UUID.
UUIDs of GATT services which are hosted on a BLE peripheral device.
Proximity UUID of iBeacon.
What you should know about "UUIDs of GATT services":
BLE peripheral devices may implement a GATT server.
A GATT server hosts GATT services.
What the API "android.bluetooth.BluetoothGatt.getServices()" returns is a list of GATT services (List<BluetoothGattService>).
BluetoothGattService.getUuid() returns the ID of the service.
What you should know about "Proximity UUID of iBeacon":
BLE peripheral devices broadcast advertising packets.
The payload part of an advertising packet contains a list of AD structures.
An AD structure consists of (1) Length (1 byte), (2) AD Type (1 byte) and (3) AD Data. The AD structure format is described in "11 ADVERTISING AND SCAN RESPONSE DATA FORMAT" of "Bluetooth Core Specification 4.2".
iBeacon is a kind of AD structures.
AD Type of iBeacon is 0xFF (which means Manufacturer Specific Data).
The first 4 bytes of AD Data of iBeacon are 0x4C, 0x00, 0x02 and 0x15. The first 2 bytes (0x4C, 0x00) mean "Apple, Inc." and the next 2 bytes (0x02, 0x15) mean "iBeacon format".
Proximity UUID (16 bytes), major number (2 bytes in big endian), minor number (2 bytes in big endian), and power (1 byte) follow the first 4 bytes.
So, what you have to do to get iBeacon information (Proximity UUID, major, minor, power) are as follows.
Parse a payload of an advertising packets as a list of AD structures.
For each AD structure, check if AD Type is 0xFF and the first 4 bytes of AD Data are 0x4C, 0x00, 0x02 and 0x15.
When the conditions of 2. are satisfied, parse the remaining bytes as Proximity UUID, major number, minor number, and power.
If you use nv-bluetooth, you can extract iBeacon from an advertising packet like the following:
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)
{
// Parse the payload of the advertising packet.
List<ADStructure> structures =
ADPayloadParser.getInstance().parse(scanRecord);
// For each AD structure contained in the advertising packet.
for (ADStructure structure : structures)
{
if (structure instanceof IBeacon)
{
// iBeacon was found.
IBeacon iBeacon = (IBeacon)structure;
// Proximity UUID, major number, minor number and power.
UUID uuid = iBeacon.getUUID();
int major = iBeacon.getMajor();
int minor = iBeacon.getMinor();
int power = iBeacon.getPower();
........
See "iBeacon as a kind of AD structures" for details.
RadiusNetworks has "re-released" the libraries and examples in conjunction with a new cross platform beacon proximity spec.
New AltBeacon Standard Allows Cross-Platform Proximity Apps
Check out altbeacon.org.