Does anyone know if the collection given by the interface RangeNotifier is ordered by approximate distance from the device, with the closest beacons at the beginning of the array like in iOS?
didRangeBeaconsInRegion(java.util.Collection iBeacons, Region region)
Thanks
No, the list is ordered by the time when the iBeacon Bluetooth LE advertisement was detected at the Android device. This may be inconsistent between each scan cycle (i.e. each call to the RangeNotifier), so you probably want to sort the list yourself if you want a specific order.
Related
I created an android (java) application that uses the altbeacon library (github page) to detect beacons via the Bluetooth module.
The Beacons are configured with Eddystone UID, protocol with an advertising interval of 100ms and transmit power level of strong (10dBm).
What I would like to be able to do is to detect the RSSI value of the beacons with a frequency of 10Hz (i.e. 100ms).
I've already prepared a service that implements the altbeacon library, the relevant part are showed below:
mBeaconManager = BeaconManager.getInstanceForApplication(this);
beaconRegion = new Region("beacon_region", null, null, null);
// use Eddystone protocol
mBeaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT));
mBeaconManager.setAndroidLScanningDisabled(true);
mBeaconManager.setForegroundScanPeriod(100l); // scan frequency
mBeaconManager.setForegroundBetweenScanPeriod(0);
and the callback didRangeBeaconsInRegion from which I see the beacons and get the RSSI value is this:
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
Log.i(BeaconDataCollectorService.class.getSimpleName(), String.format("Found %s beacons in range", beacons.size()));
}
What's my problem?
Running the app, I notice that within didRangeBeaconsInRegion, I often don't see all the beacons.
I ran the data collection for a few seconds, creating a csv format of the data obtained, where you can see that I often have 0s (indicating that the beacon was not detected); I put the sharing of this csv on pastebin (https://pastebin.com/zkUZC5R4)
How can I improve the scan frequency by always being able to detect all the beacons?
altbeacon version used:
implementation 'org.altbeacon:android-beacon-library:2.16.3'
Android version: 9
Thanks
Unfortunately, the library is not designed to do this, as the ranging APIs are modeled after iOS equivalents which give aggregate detections at fixed intervals as opposed to access to individual packets when they arrive.
The main reason you often get 0 beacons detected with such a short scan period is because the scan is turned on and off every 100ms, and it takes 10ms or so to start and stop. This gives a good probability of missing the detection.
Here's the good news: If the library ever detects two beacon packets in the same scan period then it will stop turning the scan off and your detection rate will improve. But getting it to detect two beacons in 100ms is nearly impossible of your beacon advertises at a nominal 10Hz.
One thing you might try is to start by setting the scan period to 1 second. After you have detected a finite number of your beacons for 10 secs or so, there is a very good chance you will have detected two beacons in one scan cycle and then you can switch to a scan period of 100ms and get a higher detection rate.
You will never get a 100% detection rate for two reasons:
Not all beacon packets transmitted are received due to collisions and radio noise. At close range 80-90% is typical.
"BLE advertisers do not advertise at regular intervals. They randomize when their packets are sent to avoid collisions. A nominal 10Hz transmitter might have anywhere between 70ms and 140ms between individual packets, so for fixed scan cycles of 100ms sometimes there will be 0, 1 or 2 Packers eligible to be received.
If you really need to get callbacks on every detection, you might try setting up a NonBeaconBleScanCallback in the BeaconManager, then calling BeaconManager.clearBeaconParsers(). This will cause all beacons detections to be sent to that callback immediately when detected. You will then have to construct a new BeaconParser for use inside that callback to decode the beacon from the raw packet. Use beaconParser.parse(...)
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.
What I Know is,
Broadcasting Power (or Transmit Power) is the power with which the beacon broadcasts its signal. The maximum range of the broadcast signal depends on this.
As I was going through the Kontakt.io blog they says that, Tx power level can be adjusted by the user whose value varies between 0-7(in case of Kontakt beacons & can be different for other beacons). For more info please go through
this link.
The advertising packets sent by beacon contains the information about calibrated Tx Power(RSSI power value at 1 meter).
My question is that,
Is it possible to get broadcasting power , the signal power that beacon sends from the source (as mentioned above the value varies between 0-7) (not the calibrated Tx Power) from BLE APIs?
I had observed that result returned by the toString() method of ScanResult class contains mTxPowerLevel which is same for different beacons(mTxPowerLevel=-2147483648).
My other question is that, what is this mTxPowerLevel?
If my way of understanding is wrong, please guide to go in a right direction. Thank you!!
learner,
Using the Kontakt.io Android SDK you can receive this value from range 0-7 (or in case of Beacon Pros 1-7). Here you can find the Quickstart guide for the newest right now SDK 3.2.1.
Here you can find how to implement simple ranging for the beacons on Android.
Let it be that your beacons broadcast the iBeacon packet, so using iBeacon Listener when you discover the beacon simply use
ibeacon.getTxPower()
What I need is to get a list of every devices in my range so I can call a certain method on them one after another.
What I have tried so far is to use the startDiscovery() method of the BluetoothAdapter and while it returns a list of devices it takes about 12 seconds to complete which is a lot for my task to complete.
I also managed to user the LeScanCallback succesfully every 2-3 seconds and I do discover devices, but on every scan it returns only one device at a time.
I'm trying to search for Beacons so this type of method could return every call a single other device that uses BlutoothLE when it's found ,while not returning my Beacon's info at all.
So, is there a way to discover a list of all devices in a range without waiting for the startDiscovery() to finish after 12 seconds ?
A few points:
startDiscovery is intended for bluetooth classic devices, not Bluetooth LE.
Android does not contain any APIs specific to parsing beacons, only for dealing with raw Bluetooth LE devices.
You can use the free and open source Android Beacon Library add-on to detect and parse beacons. It does not have a 12 second delay and wraps the LeScanCallback method and combines the results so you can get callbacks every second like:
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for (Beacon beacon : beacons) {
Log.i(TAG, "I see a beacon:"+beacon+" that is "+beacon.getDistance()+" meters away.");
}
}
You need to call startScan(ScanCallback) api of BluetoothLeScanner to start scanning, this has support on Android 21(5.0).
Also look below question, it has sample code you can use to start/stop Le Scanning.
How to restart BluetoothLeScanner?
I was wondering :
When we enter a shop, using the app shop, we receive for example a notification.
But what if the beacon is down, and it's replaced with another beacon, with a different UUID etc .. ? Are the UUID/Major/Minor value of a beacon not harcoded but in a database on the server ? How it's fetched ?
Thanks you
The UUID of an iBeacon is not related in any way to its MAC address. It is a value that is assigned to the beacon by the beacon owner. Some beacon vendors have a specific UUID or range of UUIDs while others allow any UUID to be used.
If a particular beacon failed then the replacement would likely be configured with the same UUID.
When the app detects a particular beacon it needs to refer to some database, either in the app or on a server, that gives "meaning" to the particular UUID/major/minor combination so it is possible that the database could be updated to reflect the new hardware but this is less likely than simply configuring the replacement hardware with the same values
It is a good practice to not hard code your beacon identifiers in your app. You can build your app so on launch, it contacts a web service to download a list of identifiers to search for. You can build your own or use an off the shelf service like my company's ProximityKit that does exactly this.
Of course, if you are relying on beacon detections to launch your app, your app won't get auto launched to download the new beacon identifiers if the beacon ids change in advance. The user will have to manually do the launch to get the new list.
There are a few ways around this:
Set the identifiers on replaced beacons so they are the same as the old ones.
If you know you cannot set the identifiers, broaden the beacon region filter for auto launch so it matches a wide variety of beacon identifiers. On iOS you can search for all beacons with a shared UUID. On Android, you can search for all beacons regardless of identifiers.
When you initialise Beacon Region then you need to identify at least UUID and it is either hardcoded with in the app or can be placed on the server and should be retrieved from server before calling initialising Beacon Region.
NOTE:You should have a copy of all beacons UUIDs,majors and minors for future purposes
But suppose your Beacon goes out of order then there's a backup plan.
Follow below said steps:
1.Install Estimote-iOS or android app
2.Place the new beacon near to your device and start ranging beacons in estimote app.
3.Then you need to login with your cloud account in your app and configure new beacon(i.e edit your beacon's UUID.)You can even edit major,minor etc
4.Save those settings and your new beacon is configured and ready to use.
Happy Coding :)