0

I am trying to notify the user when the user enters a region defined and also when the user exits the region. This is what i have done so far. I used to use the rangeNotifier method (didBeaconsEnterRange) in order to notify a user when he/she enters a region, but then this method would get called every 1 second, so i moved the notification logic to the monitorNotifier class (didEnterRegion) method.

My application class extends BootStrapNotifier, and i am setting the scanPeriod to 2000s instead of the default 1100l seconds, because i seem to receive exit and entry notifications way too quick, even when the beacon is in range. Earlier i even increased the timeout period from 10000ms to 20000ms that would fire the exit when a beacon doesnt fire signals within the timeout period.

Code snippet for myapplication class

BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
    beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(LAYOUT_HERE));
    beaconManager.setForegroundScanPeriod(2000l);
    beaconManager.setBackgroundBetweenScanPeriod(1100l);
    //beaconManager.setBackgroundScanPeriod(5000l);
    beaconManager.setDebug(true);

    Log.d(TAG, "setting up background monitoring for beacons and power saving");
    // wake up the app when a beacon is seen
    mRegion = new Region("myRangingUniqueId",
            null, null, null);
    setRegionAgain();

SetRegionAgain method

if(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "").trim().length() > 0) {
        if(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "").trim().length() > 0 ) {
            try {
                mRegion = new Region("myRangingUniqueId",
                        Identifier.parse(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "")), 
                        null, null);
            }catch(IllegalArgumentException e) {
                e.printStackTrace();
                mRegion = new Region("myRangingUniqueId",
                        null, null, null);
            }
        }
    }

    regionBootstrap = new RegionBootstrap(this, mRegion);

    // simply constructing this class and holding a reference to it in your custom Application
    // class will automatically cause the BeaconLibrary to save battery whenever the application
    // is not visible.  This reduces bluetooth power usage by about 60%
    backgroundPowerSaver = new BackgroundPowerSaver(this);

I have a background service that does the notification work, so it implements the BeaconConsumer interface. Code snippet below:

OnStart method:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    flagToCheckExit = false;
    mHandler = new Handler();
    beaconManager.bind(this);
    if (beaconManager.isBound(this)) beaconManager.setBackgroundMode(false);
    return Service.START_STICKY;
}

onDestroy method:

@Override
public void onDestroy() {
    super.onDestroy();
    try {
        beaconManager.stopMonitoringBeaconsInRegion(CommonUtilities.getRegion());
// this region is the one that i use to monitor (singleton types)
    } catch (RemoteException e) {
        e.printStackTrace();
    }

    beaconManager.unbind(this);
}

onServiceConnected method:

@Override
public void onBeaconServiceConnect() {
    beaconManager.setMonitorNotifier(new MonitorNotifier() {

        @Override
        public void didExitRegion(final Region region) {
            LogManager.d(TAG, "didExitRegion %s", region);

            if(SharedPrefs.getString(SharedPrefs.USER_ID, "").trim().length() > 0) {
                flagToCheckExit = true;
// i use this flag to prevent random entry and exit notifications
                mHandler.postDelayed(mRunnable, 20000);
// waiting for 20seconds before firing an exit notification, since an entry notification might get fired immediately after the exit
            }
        }

        @Override
        public void didEnterRegion(Region region) {
            Log.e(TAG,"region id1 >>> " + ((region.getId1() == null) ? "null" : region.getId1().toUuidString()));

            LogManager.d(TAG, "didEnterRegion %s ",region);

            if(!flagToCheckExit) {
                if(SharedPrefs.getString(SharedPrefs.USER_ID, "").trim().length() > 0) {
                    if(region.getId1() != null && 
                            region.getId1().toUuidString().equalsIgnoreCase(SharedPrefs.getString(SharedPrefs.iBEACON_ID, ""))) {
                        if(!SharedPrefs.getBoolean(SharedPrefs.IS_ENTRY_LOG_CALLED, false)) {
                            String entryRange = getAppContext().getString(R.string.entered_beacon_region);
                    CommonUtilities.sendNotification(MonitoringAltBeaconService.this,entryRange,1);
                        }
                    }
                }
            }else {
                // invalidate the handler
                // stop all operations of the handler
                // we do this to prevent an exit getting called since entry has been called immediately.
                mHandler.removeCallbacks(mRunnable);
            }
        }

        @Override
        public void didDetermineStateForRegion(int state, Region region) {
            LogManager.d(TAG, "didDetermineStateForRegion %s ",region);
        }
    });

    startMonitoring();
}

startMonitoring method:

private void startMonitoring() {
    try {
        if(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "").trim().length() > 0 ) {
            try {
                beaconManager.startMonitoringBeaconsInRegion(CommonUtilities.getRegion());
            }catch(IllegalArgumentException e) {
                e.printStackTrace();

                beaconManager.startMonitoringBeaconsInRegion(CommonUtilities.getRegion());
            }
        }
    } catch (RemoteException e) {   }
}

the runnable thread:

Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
        SharedPrefs.putBoolean(SharedPrefs.IS_ENTRY_LOG_CALLED, false);
        SharedPrefs.putBoolean(SharedPrefs.IS_EXIT_LOG_CALLED, true);

        String exitedRange = getAppContext().getString(R.string.exited_beacon_region);
        CommonUtilities.sendNotification(MonitoringAltBeaconService.this,exitedRange,2);
        LogManager.d(TAG, "exit called");
        flagToCheckExit = false;
    }
};

There is a strange behavior with this, there are multiple entry and exit logs that i get even when the beacon device is in range, i get the exit. I tried bypassing the exit notification but it seems to fail with the logic (patch) above.

Log:

03-19 18:00:25.866: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:00:25.867: D/MonitoringAltBeaconService(22795): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-19 18:00:26.470: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 

03-19 18:00:26.477: D/MonitoringAltBeaconService(22795): didEnterRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 

03-19 18:00:48.076: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:00:48.076: D/MonitoringAltBeaconService(22795): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null

03-19 18:00:51.275: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:00:51.282: D/MonitoringAltBeaconService(22795): didEnterRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:01:10.269: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-19 18:01:10.269: D/MonitoringAltBeaconService(22795): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-19 18:01:15.876: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:01:15.883: D/MonitoringAltBeaconService(22795): didEnterRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 

I am using AprilBeacon. The app i am working on is held up because the beacons dont generate notifications correctly. Please assist.

EDIT:

the device i use if Motorolla g2, this scenario happens in both the kitkat as well as lollipop versions. And Wifi is on, i prefer it being on, since there are webservice calls involved, when an entry exit is determined. Realtime , it would not be encouraged to ask users to switch their wifi off :(..

The library i use is , android-beacon-library the one here, and i am afraid i do not know the frequency at which the april beacon sends out signals.

EDIT 2:

Log 1 can be found here

Log 2 can be found here

EDIT 3

log when wifi is switched off I noticed that i did get an exit even when the beacon was in range And i opened the locate app, and it showed no beacons are there (see screenshot). i removed the battery and put them back it got the beacon, and so did my app too. (but in real life, i am sure batteries will not be tampered with)

When not detected After removing the batteries

Marian Paździoch
  • 8,813
  • 10
  • 58
  • 103
  • I understand about not wanting to turn off WiFi, but can you please try that as a troubleshooting step and let us know if it makes any difference? It will help to track the problem down. – davidgyoung Mar 20 '15 at 11:32

3 Answers3

2

Your configuration seems to valid but there is a little flaw. You should have set both foreground scan configs:

beaconManager.setForegroundScanPeriod(2000l);
beaconManager.setForegroundBetweenScanPeriod(1100l);
//Update default time with the new one
beaconManager.updateScanPeriods();

or/and background scan configs:

beaconManager.setBackgroundScanPeriod(2000l);
beaconManager.setBackgroundBetweenScanPeriod(1100l);
//Update default time with the new one
beaconManager.updateScanPeriods();

Also, do you know advertisement frequency of the beacon ? You have said that you have increased scan period to 20secs and nothing changed still frequency would be helpful for us to help you.

Btw, can you also share AltBeacon's logcat outputs? Also, what is your device and model ? And which Android version is it running ? And which AltBeacon library version are you using?

If your device is running Lollipop try with following line and please share results with us:

BeaconManager.setAndroidLScanningDisabled(true);

Also, try with turning of your WiFi if it is on because in some devices it interferes Bluetooth scan.

Btw, sorry this is more like a comment than an answer but it was to long for a comment as well :).

Furkan Varol
  • 252
  • 2
  • 8
  • Please check the edit in the question. I will need some time before i can post AltBeacon's logs. i just missed out on taking the logs. – Rat-a-tat-a-tat Ratatouille Mar 20 '15 at 09:12
  • Can you test with turning off your WiFi ? I know in reality, you can not assume that WiFi is off or force user to turn it off but at least we can be sure about it. Btw, actually I was asking which AltBeacon Library version you are using. Sorry for confusion. – Furkan Varol Mar 20 '15 at 09:23
  • hi, where do i get the version from? its no where in the folders. i downloaded it a week ago. – Rat-a-tat-a-tat Ratatouille Mar 20 '15 at 10:40
  • hi, iv added the logs ,alt beacon logs, if that help. – Rat-a-tat-a-tat Ratatouille Mar 20 '15 at 10:56
  • Those links look like dead :). It says "This paste has been removed!". Btw, have you run [reference app](https://github.com/AltBeacon/android-beacon-library-reference) on your device ? If you didn't, please test with it so that we can understand whether there is a problem with the library or your code. Also, test with [Locate App](https://play.google.com/store/apps/details?id=com.radiusnetworks.locate). – Furkan Varol Mar 20 '15 at 11:32
  • For this use case, I think the between scan period should be 0l. – davidgyoung Mar 20 '15 at 11:33
  • il try trouble shooting the same with wifi off.. also please find the log links fixed. and il download the app too and check. – Rat-a-tat-a-tat Ratatouille Mar 20 '15 at 11:41
  • @davidgyoung, Furkan - iv added the images, and log also when wifi is switched off. i did get an exit even whn the beacon was in range :S.. when wifi is switched off. – Rat-a-tat-a-tat Ratatouille Mar 20 '15 at 12:12
2

The problem is a combination of an infrequently advertising beacon, and a custom background scan interval that is too short.

It appears that the beacon is only advertising once every 2 seconds because that is the closest I ever see two subsequent detection timestamps in the log. This is low transmission frequency is problematic, and exacerbated by the custom settings.

For proper operation of the library, the background 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.

The default library settings set a background scan period to 10 seconds, which should be enough to give a very high probability of detecting even a beacon transmitting only once every 2 seconds, and making incorrect region exits very, very rare.

Recommendations:

  1. Change the background scan period to be at least the default of 10 seconds. To save battery, the between scan period should probably be longer, too -- the default of 5 minutes is a reasonable choice unless you have a good reason to make it shorter. If you still get exit events, make the background scan period even longer.

  2. Use different beacons that advertise more frequently. Although you should be able to make the library work with these beacons, you won't get updates as frequently, and apps like Locate will periodically show dropouts in detections. If you are doing distance estimates in your app, you need beacons that transmit at 10Hz or more. If not doing distance estimates in your app, you should still use beacons that transmit at 1Hz or more, otherwise you will be more likely to have problems like this.

How do I know this is the problem?

As you can see from the log excerpts below, an incorrect region exit happens at 15:50:52, because it has been 10 seconds since the previous detection. Any 10 second period without detections will cause a region exit event the next time a scan cycle stops. So you must be very sure that a scan cycle is long enough to capture a beacon transmission. With the custom settings, missing a detection on three subsequent scan cycles will cause a region exit.

03-26 15:49:49.533: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:49:55.567: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:01.624: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:08.898: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:11.315: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:17.380: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:21.010: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:26.440: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:30.066: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:33.108: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:36.120: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:39.745: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:41.573: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7

03-26 15:50:52.415: D/MonitorState(28596): We are newly outside the region because the lastSeenTime of 1427365241573 was 10841 seconds ago, and that is over the expiration duration of 10000
03-26 15:50:52.415: D/BeaconService(28596): found a monitor that expired: id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-26 15:50:52.415: D/Callback(28596): attempting callback via intent: ComponentInfo{com.credencys.mycarline/org.altbeacon.beacon.BeaconIntentProcessor}

03-26 15:50:54.879: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:56.705: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:51:00.940: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:51:03.348: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:51:03.349: D/BeaconService(28596): looking for ranging region matches for this beacon
03-26 15:51:03.842: D/CycledLeScanner(28596): Waiting to stop scan cycle for another 1000 milliseconds
03-26 15:51:04.730: D/MonitoringAltBeaconService(28596): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
davidgyoung
  • 63,876
  • 14
  • 121
  • 204
  • sir, i am a little confused. BootsrapNotifier, do i implement this in the application class or my service? – Rat-a-tat-a-tat Ratatouille Apr 07 '15 at 13:19
  • The BootsrapNotifier is designed to be implemented by a custom Application class. – davidgyoung Apr 07 '15 at 14:56
  • so if i create a region in the application class and then create a region with a specific uuid after login, the one in the application class will be overriden? Also, will the service receive the didEnter call or will the app class soak in the didEnter call? – Rat-a-tat-a-tat Ratatouille Apr 08 '15 at 05:34
  • If you use BootstrapNotifier, all callbacks including didEnter will go to the application class. You may change the regions at any time with calls to startMonitoringBeaconsInRegion and stopMonitoringBeaconsInRegion – davidgyoung Apr 08 '15 at 10:51
  • so, i could by pass implementing bootstrap notifier ? and just implement BeaconConsumer in my service? – Rat-a-tat-a-tat Ratatouille Apr 08 '15 at 11:54
  • Yes, that is a valid alternative. Get rid of BootstrapNotifier in your application and make a service that implements BeaconConsumer. – davidgyoung Apr 08 '15 at 12:33
  • i tried doing that but then i dint get those logs that a scan is going on , and a beacon is found and all :( so i reverted back to the old code, as i had to make a build asap .. – Rat-a-tat-a-tat Ratatouille Apr 09 '15 at 09:57
0

EDIT: After reviewing the logs I have submitted a different answer that better answers the question. Please see that answer.

I noticed from the two posted logs that the library is reporting that the app is in the background and using the Android L APIs. This causes them to use "Low Latency" detections:

03-26 15:47:21.647: D/CycledLeScannerForLollipop(28596): This is Android L. Doing a filtered scan for the background.

Low latency detections save power, but they get delayed by 5 seconds or more. This works fine for background operations, but it isn't intended for foreground operations, and should be used with the default scan intervals. You should never set a non-zero between scan interval when using these Andorid L APIs, otherwise you may get exits like you describe.

If the logs are misreporting that your app is in the background, then there may be something wrong with the setup of the BackgroundPowerSaver.

You might also try disabling the Android L APIs, and use the older 4.x scanning APIs to see if that works better for your use case. If you do this, I would also remove any special scan interval settings so not to make your configuration too complex:

beaconManager.setAndroidLScanningDisabled(true)

You will need to put that line in the onCreate of your application class before you do any other beacon processing.

davidgyoung
  • 63,876
  • 14
  • 121
  • 204
  • Sir, yes that's true the app is in the background, since that's one of the test cases too, so the log does not report anything incorrect. :) .. `You should never set a non-zero between scan interval when using these Andorid L APIs, otherwise you may get exits like you describe` - does this refer to background scanning, if i set it to zero interval, will that drain the battery? – Rat-a-tat-a-tat Ratatouille Mar 21 '15 at 04:47
  • Sorry, please ignore my statement about the non-zero between scan interval -- that only applied to a pre-release version of Android L Support. Please see my other answer. – davidgyoung Mar 21 '15 at 15:20