Android Question EasiBeacon problems

henrywood

Active Member
Licensed User
Hi
Having read that since Android (contrary to iOS) does not automatically scan for beacons in the background, I am trying to use a Timer with the easibeacon example.

I am thus trying to modify the example code's Discovery Service.

This is my code:

B4X:
#Region  Service Attributes
    #StartAtBoot: False
#End Region

Sub Process_Globals
    Public IBeaconProtocol1 As IBeaconProtocol
    Dim ScanTimer As Timer
    Dim ScanInterval As Int = 30000
End Sub

Sub Service_Create
    Dim IBeaconListener1 As IBeaconListener
    IBeaconListener1.Initialize("IBeaconListener1")
    IBeaconProtocol1.Initialize
    IBeaconProtocol1.SetListener(IBeaconListener1)
    ScanTimer.Initialize("ScanTimer", ScanInterval)
    ScanTimer.Enabled = True
  
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Sub ScanTimer_Tick
    ToastMessageShow("Timer tick", False)
    StartScan
End Sub

Sub Service_Destroy
    StopScan(True)
    Dim IBeaconProtocol1 As IBeaconProtocol
End Sub

Sub IBeaconListener1_BeaconFound(IBeacon1 As IBeacon)
    Log("IBeaconListener1_BeaconFound")
    CallSubDelayed3(Main, "BeaconFound", IBeacon1, True)
End Sub

Sub IBeaconListener1_EnterRegion(IBeacon1 As IBeacon)
    Log("IBeaconListener1_EnterRegion")
    CallSubDelayed2(Main, "BeaconArriving", IBeacon1)
End Sub

Sub IBeaconListener1_ExitRegion(IBeacon1 As IBeacon)
    Log("IBeaconListener1_ExitRegion")
    CallSubDelayed2(Main, "BeaconLeaving", IBeacon1)
End Sub

Sub IBeaconListener1_OperationError(Status As Int)
    Log("IBeaconListener1_OperationError Status="&Status)
End Sub

Sub IBeaconListener1_SearchState(State As Int)
    Log("IBeaconListener1_SearchState")
    Select State
        Case IBeaconProtocol1.SEARCH_END_EMPTY
            ToastMessageShow("Scan complete - no beacons found", False)
        Case IBeaconProtocol1.SEARCH_END_SUCCESS
            ToastMessageShow("Scan complete - one or more beacons found", False)
        Case IBeaconProtocol1.SEARCH_STARTED
            ToastMessageShow("Scan started", False)
    End Select
End Sub

Sub StartScan
    StopScan(False)
    IBeaconProtocol1.StartScan
End Sub

Sub StopScan(Reset As Boolean)
    If IBeaconProtocol1.IsScanning Then
        IBeaconProtocol1.StopScan
        ToastMessageShow("Scan stopped", False)
    End If
    If Reset Then
        '    calling Reset clears any previously found beacons
        IBeaconProtocol1.Reset
    End If
End Sub
However, I am experiencing three problems:

1. My timer gets called but the call to StartScan() does not work (ie. it does not re-scan every 30 seconds).
2. I see an exception (shown as a ToastMessage: libcore.io.ErrnoException: recvfrom failed: ETIMEDOUT (Connection timed out) when using B4ABridge ?
3. It seems that the ExitRegion handler is never called ??? EnterRegion handler is called though...


Also, an additional question (I am new to the whole beacon thing):

- How do I know that the beacon in Enter/ExitRegion Sub is one of my beacons and not somebody else's ?

Thanks

/Henrik
 

warwound

Expert
Licensed User
Take a look at the attached project.
It's more elaborate than the simple easiBeacons example i posted in the other thread.

It encapulates the functions of the easiBeacon library into a Class - a single instance of this Class is referenced as a Process Global in the Main Activity module.
You should be able to modify the project so that instance is referenced as a Process Global of a Service module if desired.

The project is designed to detect any of 3 easiBeacons i have.
These 3 easiBeacons have all been configured with the same UUID and the project will only detect easiBeacons with this UUID.

You could comment out the line in the Main Activity, line 39:

B4X:
BeaconMonitor1.SetUUIDFilter(<my UUID here>)
Or you could set the UUID filter to the UUID of your easiBeacon(s).

My three easiBeacons all have the same Major id of 1, their Minor ids are 1, 2 and 3.

Configuring your easiBeacons with a unique combination of UUID, Major and Minor ids is the way to know if any found beacons are your own beacons.
You have to assume that nobody nearby will be using beacons and have them configured with the same UUID that you have chosen - not likely but not impossible...

The application can scan once or scan repeatedly using a Timer.
Look in the Class module and you'll see i disable the Timer in it's Tick event, perform a scan and then re-enable the Timer.
Could your exception be caused by your Timer Tick event being raised while a scan is already in progress?
Disabling the Timer while a scan is in progress would prevent such an exception.

So the application performs a scan for beacons and when the scan completes it populates a ListView with all found beacons.
Displaying the beacon's Major and Minor ids along with their proximity and battery level.
(Screengrab attached).

Compile and run the project and look in the log.
It's pretty self explanatory.
You'll see comments such as 'BeaconMonitor: callback sub ??? not found'.
The Class will raise events in the Activity if the corresponding callback sub exists in the Activity.
If you uncomment these lines in the Activity:

B4X:
'Sub BeaconMonitor_BeaconFound(IBeacon1 As IBeacon)
'	this event currently not used
'End Sub

'Sub BeaconMonitor_EnterRegion(IBeacon1 As IBeacon)
'	this event currently not used
'End Sub

'Sub BeaconMonitor_ExitRegion(IBeacon1 As IBeacon)
'	this event currently not used
'End Sub
Replace the comment "' this event currently not used" with a Log statement, you should see those callback subs now executed.

Look at the Class method 'Reset' - see it's comment?
Calling reset tells the library to forget about any beacons found by it's last scan.
If these last found beacons are forgotten then the library is unable to raise any 'ExitRegion' events - when it next scans and finds beacons it can't compare the beacons found by the new scan to the (forgotten) beacons found by the previous scan.
Therefore it cannot know if the android device has exited a region.

Post again if you have more questions and i'll try and help.

Martin.
 

Attachments

fishwolf

Active Member
Licensed User
Take a look at the attached project.
It's more elaborate than the simple easiBeacons example i posted in the other thread.

It encapulates the functions of the easiBeacon library into a Class - a single instance of this Class is referenced as a Process Global in the Main Activity module.
You should be able to modify the project so that instance is referenced as a Process Global of a Service module if desired.

The project is designed to detect any of 3 easiBeacons i have.
These 3 easiBeacons have all been configured with the same UUID and the project will only detect easiBeacons with this UUID.

You could comment out the line in the Main Activity, line 39:

B4X:
BeaconMonitor1.SetUUIDFilter(<my UUID here>)
Or you could set the UUID filter to the UUID of your easiBeacon(s).

My three easiBeacons all have the same Major id of 1, their Minor ids are 1, 2 and 3.

Configuring your easiBeacons with a unique combination of UUID, Major and Minor ids is the way to know if any found beacons are your own beacons.
You have to assume that nobody nearby will be using beacons and have them configured with the same UUID that you have chosen - not likely but not impossible...

The application can scan once or scan repeatedly using a Timer.
Look in the Class module and you'll see i disable the Timer in it's Tick event, perform a scan and then re-enable the Timer.
Could your exception be caused by your Timer Tick event being raised while a scan is already in progress?
Disabling the Timer while a scan is in progress would prevent such an exception.

So the application performs a scan for beacons and when the scan completes it populates a ListView with all found beacons.
Displaying the beacon's Major and Minor ids along with their proximity and battery level.
(Screengrab attached).

Compile and run the project and look in the log.
It's pretty self explanatory.
You'll see comments such as 'BeaconMonitor: callback sub ??? not found'.
The Class will raise events in the Activity if the corresponding callback sub exists in the Activity.
If you uncomment these lines in the Activity:

B4X:
'Sub BeaconMonitor_BeaconFound(IBeacon1 As IBeacon)
'    this event currently not used
'End Sub

'Sub BeaconMonitor_EnterRegion(IBeacon1 As IBeacon)
'    this event currently not used
'End Sub

'Sub BeaconMonitor_ExitRegion(IBeacon1 As IBeacon)
'    this event currently not used
'End Sub
Replace the comment "' this event currently not used" with a Log statement, you should see those callback subs now executed.

Look at the Class method 'Reset' - see it's comment?
Calling reset tells the library to forget about any beacons found by it's last scan.
If these last found beacons are forgotten then the library is unable to raise any 'ExitRegion' events - when it next scans and finds beacons it can't compare the beacons found by the new scan to the (forgotten) beacons found by the previous scan.
Therefore it cannot know if the android device has exited a region.

Post again if you have more questions and i'll try and help.

Martin.
where i found the imaginear.api.easibeacon library?

Thanks
 

warwound

Expert
Licensed User
in this post is see only the "easibeacon" library not the "imaginear.api.easibeacon" library
They are more or less the same...
I initially developed the easiBeacon library for Imaginear - this library had the java package name imagineear.api.easibeacon.
Imagineear gave me permission to upload the library to the forum so i recompiled it with a different java package name 'uk.co.martinpearman.b4a.easibeacon'.

One of the code examples i uploaded was using the Imagineear library so b4a complains that it cannot find 'imaginear.api.easibeacon'.
You just need to ensure that the Easibeacon library is checked in the library list and save the project - it'll update it's references from 'imaginear.api.easibeacon' to 'uk.co.martinpearman.b4a.easibeacon' and work as expected.

Martin.
 

bioident

Member
Licensed User
Hi,

I have a problem application not finf beacons
I get null object reference:
uk.co.martinpearman.b4a.easibeacon.IBeaconProtocol.GetIBeaconsByProximity()' on a null object reference

Please help why:

LogCat connected to: B4A-Bridge: samsung SM-G900F
--------- beginning of main
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Service (service1) Create **
** Service (service1) Start **
Connected to B4A-Bridge (Wifi)
Installing file.
** Activity (main) Pause, UserClosed = false **
PackageAdded: package:b4a.easibeaconsdemo
Copying updated assets files (3)
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
BeaconMonitor: listener added
** Activity (main) Pause, UserClosed = false **
BeaconMonitor: listener removed
** Activity (main) Resume **
BeaconMonitor: listener added
** Activity (main) Pause, UserClosed = false **
BeaconMonitor: listener removed
sending message to waiting queue (OnActivityResult)
running waiting messages (1)
on result
** Activity (main) Resume **
BeaconMonitor: listener added
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
** Activity (main) Pause, UserClosed = false **
BeaconMonitor: listener removed
** Activity (main) Resume **
BeaconMonitor: listener added
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
** Activity (main) Pause, UserClosed = false **
BeaconMonitor: listener removed
** Activity (main) Resume **
BeaconMonitor: listener added
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
BeaconMonitor: ScanIdle
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
BeaconMonitor: ScanIdle
** Activity (main) Pause, UserClosed = true **
BeaconMonitor: listener removed
sending message to waiting queue (CallSubDelayed - BeaconMonitor_ScanComplete)
sending message to waiting queue (CallSubDelayed - BeaconMonitor_ScanIdle)
sending message to waiting queue (ibeaconlistener_searchstate)
sending message to waiting queue (ibeaconlistener_searchstate)
** Activity (main) Create, isFirst = false **
running waiting messages (4)
Error occurred on line: 48 (BeaconMonitor)
java.lang.NullPointerException: Attempt to invoke virtual method 'uk.co.martinpearman.b4a.easibeacon.IBeacon[] uk.co.martinpearman.b4a.easibeacon.IBeaconProtocol.GetIBeaconsByProximity()' on a null object reference
at b4a.easibeaconsdemo.beaconmonitor._getibeaconsbyproximity(beaconmonitor.java:216)
at b4a.easibeaconsdemo.main._beaconmonitor_scancomplete(main.java:535)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:636)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:302)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:238)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:121)
at anywheresoftware.b4a.keywords.Common$5$1.run(Common.java:966)
at anywheresoftware.b4a.BA.setActivityPaused(BA.java:404)
at b4a.easibeaconsdemo.main.afterFirstLayout(main.java:104)
at b4a.easibeaconsdemo.main.access$100(main.java:17)
at b4a.easibeaconsdemo.main$WaitForLayout.run(main.java:78)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5832)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Installing file.
PackageAdded: package:b4a.easibeaconsdemo
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
BeaconMonitor: listener added
BeaconMonitor: ScanStart
** Activity (main) Pause, UserClosed = false **
BeaconMonitor: listener removed
** Activity (main) Resume **
BeaconMonitor: listener added
BeaconMonitor: ScanComplete
BeaconMonitor: ScanIdle
BeaconMonitor: ScanIdle_Tick
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
BeaconMonitor: ScanIdle
BeaconMonitor: ScanIdle_Tick
BeaconMonitor: ScanStart
BeaconMonitor: ScanComplete
BeaconMonitor: ScanIdle
** Activity (main) Pause, UserClosed = false **
BeaconMonitor: listener removed
 
Top