I configure android beacon library to detect Eddystone packets
beaconManager = BeaconManager.getInstanceForApplication(context);
// Detect the main identifier (UID) frame:
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
// Detect the telemetry (TLM) frame:
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("x,s:0-1=feaa,m:2-2=20,d:3-3,d:4-5,d:6-7,d:8-11,d:12-15"));
// Detect the URL frame:
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("s:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-21v"));
beaconManager.bind(this);
Beacon in never detected in Android beacon library.
#Override
public void onBeaconServiceConnect() {
beaconManager.addMonitorNotifier(this);
beaconManager.addRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons,
Region region) {
if (beacons.size() > 0) {
Extra.log("Beacons detected", "info");
//Process beacons data...
}
}
});
try {
beaconManager.startRangingBeaconsInRegion(new Region(
"myRangingUniqueId", null, null, null));
} catch (RemoteException e) {
}
}
Test:
If beacon is configured in Eddystone-TML I can detect beacon telemetry data with manufacturer app.
If beacon is configured in Eddystone-TML I canĀ“t detect beacon with library.
If beacon is configured in Eddystone-UID I can detect correctly beacon with library and manufacturer app.
Two things to check to make sure you are not detecting at all:
Make sure onBeaconServiceConnect() gets called. Add a Log.d statement to be sure.
Make sure your app has obtained location permissions if you are testing on Android 6+. See here for more info.
EDIT: For Eddystone-TLM, the library does not provide a separate beacon instance in the ranging callback. The library intead treats this frame type as supplemental to a primary beacon frame like AltBeacon or Eddystone-UID. So it will only provide the info from Eddystone-TLM if another primary beacon frame is also detected coming from the same device.
The way it works is that when a beacon frame like AltBeacon or Eddystone-UID is detected, a Beacon object is created and passed to the ranging callback. When an Eddystone-TLM frame is detected coming from the same MAC address as the a primary beacon frame, the telemetry information is attached to the object of the primary beacon frame. To access this info you call:
// Do we have telemetry data?
if (beacon.getExtraDataFields().size() > 0) {
long telemetryVersion = beacon.getExtraDataFields().get(0);
long batteryMilliVolts = beacon.getExtraDataFields().get(1);
long pduCount = beacon.getExtraDataFields().get(3);
long uptime = beacon.getExtraDataFields().get(4);
Log.d(TAG, "The above beacon is sending telemetry version "+telemetryVersion+
", has been up for : "+uptime+" seconds"+
", has a battery level of "+batteryMilliVolts+" mV"+
", and has transmitted "+pduCount+" advertisements.");
}
Related
I am using the Android beacon library with,
version -
compile 'org.altbeacon:android-beacon-library:2.15.1'
I am trying to develop one APK for transmitting multiple beacons from my mobile device.
I need to perform this to test or POC to test, how many beacons a reader can read at a time.
I am using the below code to transmit the BLE messages with Android Beacon Library.
btn_transmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isBluetoothEnabled)
{
try
{
String customUuid = "";
for(int i=0;i<=50;i++)
{
if( i < 10){
customUuid = "99999999-b00"+i+"-4807-b747-9aee23508620";
} else if ( i < 999){
customUuid = "99999999-b0"+i+"-4807-b747-9aee23508620";
}
Thread.sleep(5000);
trasmitClick(customUuid);
beaconTransmitter = null;
}
}
catch(Exception e)
{
Toast.makeText(BeaconTransmitterActivity.this, "Something went wronggg", Toast.LENGTH_LONG).show();
}
}
else
Toast.makeText(BeaconTransmitterActivity.this, "Check your bluetooth connection", Toast.LENGTH_LONG).show();
}
});
Here above I am dynamically trying to create 50 new Id's to transmit the beacons.
Method to createBeacon and transmit its advertisements
public void trasmitClick(String customUuid) {
if (beaconTransmitter == null) {
String major, minor, uuid;
uuid = customUuid;
major = etMajorValue.getText().toString().trim();
minor = etMinorValue.getText().toString().trim();
if (TextUtils.isEmpty(uuid))
uuid = customUuid;
if (TextUtils.isEmpty(major))
major = "8";
if (TextUtils.isEmpty(minor))
minor = "2";
currentType=beaconLayout;
currentuuid=uuid;
currentmajorValue=major;
currentminorValue=minor;
beacon = new Beacon.Builder()
.setId1(uuid)
.setId2(major)
.setId3(minor)
//.setManufacturer(0x0118) // It is for AltBeacon. Change this for other beacon layouts
.setManufacturer(0x004C)
.setTxPower(-59)
//.setDataFields(Arrays.asList(new Long[]{6l, 7l})) // Remove this for beacon layouts without d: fields
.build();
// Change the layout below for other beacon types
beaconParser = new BeaconParser()
.setBeaconLayout(parserLayout[beaconLayout]);
beaconTransmitter = new BeaconTransmitter(getApplicationContext(), beaconParser);
beaconTransmitter.startAdvertising(beacon, new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
}
#Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
}
});
btn_transmit.setText("Stop Advertising");
btn_apply.setEnabled(false);
} else {
beaconTransmitter.startAdvertising();
beaconTransmitter = null;
btn_transmit.setText("Start Advertising");
btn_apply.setEnabled(false);
}
}
I am able to make this code work, but what is the result is I am able to transmit only 4 messages, the rest of the messages are not being visible in the simulator.
I am trying to find if the library has some limitations or I am wrong above.
Well I am novice in Android coding.
Below is the result that I can get in my simulator:
I would like to know how can I transmit 50 messages in one go.
This is most certainly a limitation of the Bluetooth chip on your mobile phone. Different device models have different advertising limits. The Huawei P9 Lite, for example can transmit only one advertisement at a time. The Nexus 5x can advertise 10 or more. It is unlikely that many phone models (if any) support 50 simultaneous advertisements.
There is no way to know the limit programmatically, as the OS provides no API to query this limit -- you just have to try. You can check when you get an error advertising by putting code in the onStartFailure callback.
You might also use the [BeaconScope]((https://play.google.com/store/apps/details?id=com.davidgyoungtech.beaconscanner) app to test this. But remember that transmission limits are device-wide. If one app is advertising a beacon, that takes one advertisement slot away from the next app. And no, there is no way to know if other apps are advertising.
[### Expected behavior
That the lib should only fire exit when beacon has actually exited the region.
Actual behavior
The lib fires exit and enter region methods where the beacon is still in range. And this happens 20 sec apart some time more frequent some times less frequent on all android versions from 5-7
Steps to reproduce this behavior
I am running the beacon app continuously in the background as soon as the bluetooth gets turned
ON to search the beacon ,the beacon is fixed inside a car and is broadcasting at 1000s interval i have to start a ride when ever a user gets in the range and stop the ride when ever it gets out of it but the issue is that itt reports beacon Entered and Exited continuously where the user never left the beacon zone.
My code snippet
public class BackgroundBeaconScan extends Service implements BootstrapNotifier, BeaconConsumer {
#Override
public void onCreate() {
super.onCreate();
AppUtils.isBGServiceActive = true;
//AppUtils.appTerminated = false;
Log.e("Beacon", "Service Start");
Log.e("Bfpk", " *** Beacon Service is started *** ");
LoggingOperations logger = new LoggingOperations();
Thread.setDefaultUncaughtExceptionHandler(logger);
mBeaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
try {
Log.e("BG", "iam in mBeaconManager to unbind it");
mBeaconManager.unbind(this);
mBeaconManager.removeAllRangeNotifiers();
mBeaconManager.removeAllMonitorNotifiers();
mBeaconManager.removeMonitoreNotifier(this);
} catch (OutOfMemoryError e) {
Log.e("BG", "iam in mBeaconManager to unbind it excep ");
}
mBeaconManager.getBeaconParsers().clear();
//set Beacon Layout for Eddystone-UID packet
mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT));
// rideBDD = new RideBDD(getApplicationContext());
mBeaconManager.setForegroundScanPeriod(20001);
mBeaconManager.setForegroundBetweenScanPeriod(50001);
mBeaconManager.setBackgroundScanPeriod(20001);
mBeaconManager.setBackgroundBetweenScanPeriod(50001);
mBeaconManager.setBackgroundMode(true);
mBeaconManager.setDebug(true);
BeaconManager.setAndroidLScanningDisabled(true);
notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
namespace = DataHandler.getStringPreferences(AppConstants.UUID_NAME_SPACE);
instanceID = DataHandler.getStringPreferences(AppConstants.UUID_INSTANCE_ID);
Log.e("BG", "namespace :" + namespace);
Log.e("BG", "instanceID :" + instanceID);
Long currentTime = System.currentTimeMillis();
String time = formateLongToOnlyDateForServer(currentTime);
LoggingOperations.writeToFile(BackgroundBeaconScan.this,"UUID > " + time + " -- > " + namespace + " - " + instanceID);
try {
Log.e("BG", "iam in mBeaconManager.isBound");
mBeaconManager.bind(this);
Log.e("BG", "iam in mBeaconManager.bind");
} catch (OutOfMemoryError e) {
Log.e("BG", "iam in mBeaconManager.bindexce", e);
}
}
My service connect
#Override
public void onBeaconServiceConnect() {
// String preiBeaconUUID = DataHandler.getStringPreferences(AppConstants.UUID);
// postiBeaconUUID=AppUtils.addDashes(preiBeaconUUID);
Region region;
try {
Log.e("BG", "iam in onBeaconServiceConnect");
namespace = DataHandler.getStringPreferences(AppConstants.UUID_NAME_SPACE);
instanceID = DataHandler.getStringPreferences(AppConstants.UUID_INSTANCE_ID);
Identifier myBeaconNamespaceId = Identifier.parse(namespace);
Identifier myBeaconInstanceId = Identifier.parse(instanceID);
region = new Region("EdstUIDAdvertising", myBeaconNamespaceId, myBeaconInstanceId, null);
mBeaconManager.addMonitorNotifier(this);
Log.e("BG", "iam in startMonitoringBeaconsInRegion");
} catch (Exception e) {
Log.e("BG", "iam in startMonitoringBeaconsInRegionExce" + e);
e.printStackTrace();
namespace = DataHandler.getStringPreferences(AppConstants.UUID_NAME_SPACE);
instanceID = DataHandler.getStringPreferences(AppConstants.UUID_INSTANCE_ID);
Identifier myBeaconNamespaceId = Identifier.parse(namespace);
/* Identifier myBeaconInstanceId = Identifier.parse(instanceID);*/
region = new Region("EdstUIDAdvertising", myBeaconNamespaceId, null, null);
mBeaconManager.addMonitorNotifier(this);
Log.e("BG", "iam in startMonitoringBeaconsInRegion");
}
AppUtils.isBGServiceActive = true;
try {
mBeaconManager.startMonitoringBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
mBeaconManager.addMonitorNotifier(new MonitorNotifier() {
#Override
public void didEnterRegion(Region region) {
Log.e("Monitored", "entered"); this fires at the same time
enterCount++;
}
#Override
public void didExitRegion(Region region) {
Log.e("Monitored", "exited"); // this fires at the same time
}
#Override
public void didDetermineStateForRegion(int i, Region region) {
}
});
}
The
Mobile device model and OS version
Samsung note 5 (7.0) s6 (6.0) s5 (5.0) every device
Android Beacon Library version
2.12.4 // please help i am facing this issue for quiet a long time now
This is a common problem caused by intermittent detection of beacons. Understand that the library only knows when a beacon disappears (exits the region) when it hasn't been detected in a long time. The library fires region exit event if a previously seen beacon is not seen for at least 10 seconds when the scan period ends.
Recommendations:
Increase your beacon transmission rate to 10 Hz or more.
If you cannot do (1), lengthen the scanPeriod to be longer until the problem goes away.
The problem you are experiencing is likely exacerbated by the custom scanning periods set in the example code, which shows a scanPeriod of 5 seconds followed by a betweenScanPeriod of 20 seconds. If a beacon in the vicinity fails to be detected during the 5 second scanPeriod.
It's unclear why your beacons are not being detected sometimes during a 5 seconds scan you have configured. It may be that they only transmit infrequently. Some beacons send out an advertising packet only every 5 seconds or so to save battery. If this is the case, it would certainly cause the problem you describe. Even if they were set up to transmit once per second, it is sometimes possible that 5 packets in a row could be missed due to radio noise.
If you use the library's default settings it is less likely to happen because scanning is performed constantly in the foreground (making it much more likely that the beacon will be detected before an exit fires) and for 10 seconds in the background. If you cannot or do not want to increase the advertising rate of your beacons, I recommend adjusting your scanPeriod / betweenScanPeriod settings to be longer than 5 seconds every 30 seconds.
For proper operation of the library, the scan period must be at least 5x the beacon transmission period. This is because not all bluetooth packets get received due to radio noise. Having an interval that is 5x the transmission period means that there are 5 chances to receive a packet on each background scan cycle, making it very unlikely the library will miss one
I am trying to transmit the major minor id from device making it an iBeacon using library
compile 'org.altbeacon:android-beacon-library:2.9.2#aar'
the code
if (mBeaconTransmitter != null) {
mBeaconTransmitter.stopAdvertising();
}
BeaconParser beaconParser=new BeaconParser();
mBeaconTransmitter = new BeaconTransmitter(getApplicationContext(), new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
int flag= mBeaconTransmitter.checkTransmissionSupported(this);
Log.v("###WWe"," BEacon Test "+flag);
Beacon beacon = new Beacon.Builder()
.setId1("2f234454-cf6d-4a0f-adf2-f4911ba9ffa6")
.setId2(majorID)//Major
.setId3(minorID)//Minor
.setBluetoothName("Vyas Pratik")
.setBeaconTypeCode(533)
.setManufacturer(0x0075) // Choose a number of 0x00ff or less as some devices cannot detect beacons with a manufacturer code > 0x00ff
.setTxPower(-59)
.setMultiFrameBeacon(true)
.build();
// .setId2(minorID)//Major Try
// .setId3(majorID)//Minor Try
//.setBluetoothAddress(bluetoothManager.getAdapter().getAddress())
// .setDataFields(Arrays.asList(new Long[]{0l}))
mBeaconTransmitter.startAdvertising(beacon, new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
Log.v("###WWe"," Sucess "+settingsInEffect.toString());
}
#Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
Log.v("###WWe"," Error "+String.valueOf(errorCode));
}
});
However, my beacon using this code is detected in Locate app but not in beacon tools app /nearby (Google app).please guide me.
Thanks
After several trial and error trick, I got to a solution for this problem, the UUID, and manufacturer id was wrong.
so I changed it to below value and the beacon is now detecting in google near by and beacon tools aswell
Beacon beacon = new Beacon.Builder()
// .setId1("2f234454-cf6d-4a0f-adf2-f4911ba9ffa6")
// .setManufacturer(0x0118) // Choose a number of 0x00ff or less as some devices cannot detect beacons with a manufacturer code > 0x00ff
.setId1("6d234454-cf6d-4a0f-adf2-f4911ba9ffa6")
.setManufacturer(0x4c) // Choose a number of 0x00ff or less as some devices cannot detect beacons with a manufacturer code > 0x00ff
.setId2(majorID)//Major
.setId3(minorID)//Minor
.setBluetoothName("Vyas Pratik")
.setTxPower(-59)
.build();
I have seen some examples how to get the URL frame of the Eddystone beacon by ranging but not by monitoring
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for (org.altbeacon.beacon.Beacon beacon: beacons) {
if (beacon.getServiceUuid() == 0xfeaa && beacon.getBeaconTypeCode() == 0x10) {
// This is a Eddystone-URL frame
String url = UrlBeaconUrlCompressor.uncompress(beacon.getId1().toByteArray());
Log.d("Eddystone", "I see a beacon transmitting a url: " + url +
" approximately " + beacon.getDistance() + " meters away.");
}
}
}
});
on didRangeBeaconsInRegion there is a org.altbeacon.beacon.Beacon parameter. But for monitoring the didEnterRegion only has the Region as the parameter.
#Override
public void didEnterRegion(Region region) {
}
So, how do I get the url of the eddysone beacon on monitoring mode ? Is it possible?
You must use ranging APIs to read the actual identifier. While it is possible to use monitoring to detect a Eddystone-URL beacon transmission, because the frame has only a single identifier (the URL), you must monitor based on knowing that URL identifier up front (not very useful), or monitor all identifiers.
In the latter case, this creates the problem of reading the identifier since the monitoring callback only has the region object as you describe.
The solution is to range at the same time as you monitor. The ranging callbacks will give you the full list of beacons detected and give you access to the URLs.
I'm a french student in ingineering and I am learning Android language by myself. My friends and I have to create an Android app which is based on iBeacon technology. I discovered the AltBeacon library few days ago and I found it awesome but I have some questions to ask on it.
Firstly, you must understand I am a novice in programming, and my questions will be idiots for you. But please I really need help ;)
Android provides a Bluetooth.LE Api and I understood that I can use the method startLeScan() to get a BluetoothDevice.
But if I want to use the AltBeacon library which is the equivalent method who allow us to scan iBeacon devices and get an Beacon object?
Another question, If I use startLeScan() and get a BluetoothDevice, how can I transform it into Beacon in order to use AltBeacon methods ?
I am sorry for my english mistakes, I hope my questions will be understandable. Bye
This is what we use to detect iBeacons and get a beacon object in a Android service using the AltBeacon lib.
Setup the BeaconManager
BeaconManager beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.setForegroundScanPeriod(5100);
beaconManager.setForegroundBetweenScanPeriod(2000);
beaconManager.setBackgroundScanPeriod(5100);
beaconManager.setBackgroundBetweenScanPeriod(2000);
//Parse IBeacon structure
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.bind(this);
Start Ranging the beacons
private void startBeaconRangeFinderService() {
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, org.altbeacon.beacon.Region region) {
try {
if (beacons.size() > 0) {
for (Beacon b : beacons) {
processYourBeaconInThisMethod(b);
}
}
} catch (Exception ex) {
Log.e(TAG_BEACON_ACTIVITY, "Error was thrown: " + ex.getMessage());
}
}
});
try {
beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
} catch (RemoteException e) {
Log.e(TAG_BEACON_ACTIVITY, "Error was thrown: " + e.getMessage());
}
}
You can easily use the Android Beacon Library to scan for beacons and return results using the "Ranging APIs" as described here:
http://altbeacon.github.io/android-beacon-library/samples.html
If you want to directly call startLeScan() and use library code to convert the results to beacon objects, you can call the following method in the scan callback:
Beacon beacon = beaconParser.fromScanData(scanData, rssi, bluetoothDevice)
However, if using a proprietary beacon format (like from from Apple), you will need to construct a BeaconParser with the proper layout. This is proprietary info, but you can do a Google search to find out the proper way to construct a
BeaconParser for proprietary layouts.
I think nv-bluetooth is the easiest way to extract iBeacon from advertising packets. Below is a sample implementation of onLeScan method.
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.