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.
Related
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
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 am sorry if this question is not an "SO approved" type of question.
I would like to develop an app that act as a beacon (among of other functionality). This app will be installed on an Android device.
I am very new at all these Bluetooth programming and I would like to get some answers on these questions:
Can anyone point me on the right part as where to start?
How client app get notification from the beacon? Can anyone explain how it works?
Thank you and sorry for these questions.
A few points:
Yes, you can make a beacon app that sends both an iBeacon and/or an Eddystone beacon transmission from an Android device. You need a device with Android 5.0+ that supports transmission (not all do). You can see a list of such devices here. The Android Beacon Library shows how to code transmission here. There is also an off-the-shelf Locate app that supports transmission here.
It is also possible to make a transmitter beacon app on iOS, but iOS only supports transmission of iBeacon packets (you cannot transmit Eddystone on iOS), and iOS cannot transmit when the app is in the background. Android can.
If you want your client app to detect quickly in the background on iOS, you are better off with iBeacon than Eddystone. Detection of iBeacon signals is optimized in the background on iOS and is built-in. Detection of Eddystone requires extra software and is not as fast.
To send a notification on beacon discovery you simply write code in the client app that detects the unique beacon identifier then creates a local notification message keyed off the beacon identifier and sends it to the user. The important part to understand us that the client code does all of the message sending locally. All the beacon app does is transmit a unique identifier that the client app receives.
To illustrate the point about how you send local notifications based on beacon identifiers, here is some sample code for iOS. This code runs on the client app. The Beacon simply sends out a transmission with specific beacon identifiers, and the client app reads them and acts appropriately.
var lastNotificationTime = NSDate(timeIntervalSince1970: 0) // Initialize last Notification time to a long time ago
func locationManager(manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], inRegion region: CLBeaconRegion) {
// Only send notification if we have not done so in the last hour (3600 seconds)
if (lastNotificationTime.timeIntervalSinceNow < -3600.0) {
for beacon in beacons {
// Send a 20% off notification for beacon with identifiers major 1, minor 2
if beacon.major.intValue == 1 && beacon.minor.intValue == 2 {
let localNotification = UILocalNotification()
localNotification.alertTitle = "Discount 20% on all items"
dispatch_async(dispatch_get_main_queue()) {
UIApplication.sharedApplication().presentLocalNotificationNow(localNotification)
}
}
}
}
}
Full Disclosure: I am the lead developer on the Android Beacon Library open source project and the author of the Locate app.
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
}
I'm writing an app (on android) to read RSSI from bluetooth devices, for location recognition using rssi fingerprinting. I have working code for reading RSSI from non-paired and discoverable bluetooth devices that are not BT4.0/BLE. I would like to know if I get some BLE-based tags (such as stick-n-find) would I be able to read their RSSI only by putting myself (my android phone to be precise), into bt-discovery mode.
In BT Low Energy the roles are switched.
The Stick-n-find would be Advertising it's service(s) Name or other information. When you receive that Advertisement from your iOS APP you will get an RSSI value with that Advertisement.
So just do something like:
#property (strong, nonatomic) CBCentralManager *CM;
#define SERVICE_ID_STR "4d1dc300-424d-13e2-a661-0002a55dc51b"
self.CM = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
NSDictionary *scanOptions = [NSDictionary dictionaryWithObject:[NSNumber
numberWithBool:NO] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
CBUUID *peripheralUUID = [CBUUID UUIDWithString:#SERVICE_ID_STR];
[self.CM scanForPeripheralsWithServices:[NSArray arrayWithObject:myUUID]
options:scanOptions];
then when it hears the Advertisement package from a Peripheral you will get
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI {
where you get the RSSI.
If you only want a callback to didDiscoverPeripheral for the FIRST time the peripheral is heard then don't use the ScanOptions
[self.CM scanForPeripheralsWithServices:[NSArray arrayWithObject:myUUID] options:nil];
From what I gather, some Android phone manufacturers may include BLE support, but it is not currently supported by Android directly (as of 4.2 Jellybean). See Issue 33371 for more info.
It looks like BLE may be coming in the next Android version as hinted in this Google Groups discussion.