B4A Class [IoT] BeaconParser - Discover iBeacons and Eddystone beacons

The BeaconParser class parses the advertising data that is sent by BLE beacons.
It supports iBeacons, Eddystone UID and Eddystone URL formats.

Note that this class is also compatible with B4i. However it will not detect iBeacons due to the way those beacons are handled in iOS.

You do not need to connect to the beacon. All the important information is delivered in the advertising data.
Call BleManager2.Scan2(Null, True) to start scanning. The second parameter (AllowDuplicates) means that it will "find" the same devices again and again.

B4A example:

upload_2015-12-7_13-4-49.png


B4i example:

upload_2015-12-7_13-5-13.png


The distance is not accurate enough to be useful.

The main method of BeaconParser is Parse. You should call it from the DeviceFound sub:
B4X:
Sub Manager_DeviceFound (Name As String, Id As String, AdvertisingData As Map, RSSI As Double)
   Dim beacon1 As Beacon = Parser.Parse(AdvertisingData, RSSI)
   If beacon1 <> Null Then
    'a beacon was discovered.
    'find the beacon type based on the BeaconType field.
  Select beacon1.BeaconType
     Case Parser.TypeiBeacon
       Dim ib As iBeacon = beacon1.SpecificData
       Log($"iBeacon: ${ib.uuid} (${ib.major}/${ib.minor})"$)
     Case Parser.TypeEddystoneUID
       Dim euid As EddystoneUID = beacon1.SpecificData
       lLog($"Eddystone UID: ${euid.Namespace}:${euid.Instance}"$)
     Case Parser.TypeEddystoneURL
       Dim eurl As EddystoneURL = beacon1.SpecificData
      Log($"Eddystone URL: ${eurl.url}"$)
   End Select
   End If
End Sub

New version of BeaconParser was uploaded. It requires BLE v1.20+: https://www.b4x.com/android/forum/threads/ble-2-bluetooth-low-energy.59937/#post-377705

It fixes an issue when there are multiple records with the same type.
 

Attachments

  • BeaconParser_B4i.zip
    7.2 KB · Views: 680
  • BeaconParser_B4A.zip
    7.3 KB · Views: 872
Last edited:

Christian García S.

Active Member
Licensed User
Hi everybody, I have an issue.

I just implemented ebeacon parser in B4A without issues, its works perfectly.

now I want to implement in B4I and I have an issue, I received log with error:

Application_Start
Application_Active
Error occurred on line: 88 (BeaconParser)
Out of bounds. Index=0 Length=0
Stack Trace: (
CoreFoundation <redacted> + 152
libobjc.A.dylib objc_exception_throw + 38
CoreFoundation <redacted> + 0
BLE Example -[B4IArray getByteFast:] + 238
BLE Example -[b4i_beaconparser _parseeddystone::::] + 1112
CoreFoundation <redacted> + 68
CoreFoundation <redacted> + 300
BLE Example +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1786
BLE Example -[B4IShell runMethod:] + 574
BLE Example -[B4IShell raiseEventImpl:method:args::] + 2212
BLE Example -[B4IShellBI raiseEvent:event:params:] + 1442
BLE Example +[B4IDebug delegate:::] + 52
BLE Example -[b4i_beaconparser _parse:::] + 524
BLE Example -[b4i_main _manager_devicefound::::] + 904
CoreFoundation <redacted> + 68
CoreFoundation <redacted> + 300
BLE Example +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1786
BLE Example -[B4IShell runMethod:] + 574
BLE Example -[B4IShell raiseEventImpl:method:args::] + 2212
BLE Example -[B4IShellBI raiseEvent:event:params:] + 1442
BLE Example +[B4IObjectWrapper raiseEvent:::] + 220
BLE Example -[BleDelegate centralManager:didDiscoverPeripheral:advertisementData:RSSI:] + 508
CoreBluetooth <redacted> + 906
CoreBluetooth <redacted> + 638
CoreBluetooth <redacted> + 84
CoreBluetooth <redacted> + 50
libdispatch.dylib <redacted> + 10
libdispatch.dylib <redacted> + 22
libdispatch.dylib <redacted> + 854
libdispatch.dylib <redacted> + 886
libdispatch.dylib _dispatch_main_queue_callback_4CF + 596
CoreFoundation <redacted> + 8
CoreFoundation <redacted> + 848
CoreFoundation CFRunLoopRunSpecific + 470
CoreFoundation CFRunLoopRunInMode + 104
GraphicsServices GSEventRunModal + 80
UIKit UIApplicationMain + 150
BLE Example main + 108
libdyld.dylib <redacted> + 2
)

The beacon is a ibeacon not an eddystone, I have B4I version 3.60 and the BLE 2.0 thats includes this version.

Later I uncomment this lines:

For Each key As Int In AdvertisingData.Keys
Log($"${key}= ${bc.HexFromBytes(AdvertisingData.Get(key))}"$)
Next

And I get this:

Cannot parse: kCBAdvDataServiceData

Thanks a lot for your help.
 

Hypnos

Active Member
Licensed User
Longtime User
The BeaconParser class parses the advertising data that is sent by BLE beacons.
It supports iBeacons, Eddystone UID and Eddystone URL formats.

Note that this class is also compatible with B4i. However it will not detect iBeacons due to the way those beacons are handled in iOS.

You do not need to connect to the beacon. All the important information is delivered in the advertising data.
Call BleManager2.Scan2(Null, True) to start scanning. The second parameter (AllowDuplicates) means that it will "find" the same devices again and again.

B4A example:

View attachment 39506

B4i example:

View attachment 39507

The distance is not accurate enough to be useful.

The main method of BeaconParser is Parse. You should call it from the DeviceFound sub:
B4X:
Sub Manager_DeviceFound (Name As String, Id As String, AdvertisingData As Map, RSSI As Double)
   Dim beacon1 As Beacon = Parser.Parse(AdvertisingData, RSSI)
   If beacon1 <> Null Then
    'a beacon was discovered.
    'find the beacon type based on the BeaconType field.
  Select beacon1.BeaconType
     Case Parser.TypeiBeacon
       Dim ib As iBeacon = beacon1.SpecificData
       Log($"iBeacon: ${ib.uuid} (${ib.major}/${ib.minor})"$)
     Case Parser.TypeEddystoneUID
       Dim euid As EddystoneUID = beacon1.SpecificData
       lLog($"Eddystone UID: ${euid.Namespace}:${euid.Instance}"$)
     Case Parser.TypeEddystoneURL
       Dim eurl As EddystoneURL = beacon1.SpecificData
      Log($"Eddystone URL: ${eurl.url}"$)
   End Select
   End If
End Sub

New version of BeaconParser was uploaded. It requires BLE v1.20+: https://www.b4x.com/android/forum/threads/ble-2-bluetooth-low-energy.59937/#post-377705

It fixes an issue when there are multiple records with the same type.


Hi All,

I want to use a raspberry pi to monitor my beacons instead of an android phone, so I tried to install this example in Raspberry Pi 3 for some test (Android Things platform)

I got the following error, is that error mean that I can't use BLE in Things platform yet?

Thanks!

B4X:
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
starter_scan (java line: 208)
java.lang.RuntimeException: Error starting scan.
    at anywheresoftware.b4a.objects.BleManager2.Scan2(BleManager2.java:142)
    at b4a.example.starter._scan(starter.java:208)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:186)
    at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:1044)
    at anywheresoftware.b4a.keywords.Common.CallSubNew(Common.java:978)
    at b4a.example.main._btnscan_click(main.java:373)
    at b4a.example.main._activity_create(main.java:343)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:186)
    at b4a.example.main.afterFirstLayout(main.java:102)
    at b4a.example.main.access$000(main.java:17)
    at b4a.example.main$WaitForLayout.run(main.java:80)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
 

Christian García S.

Active Member
Licensed User
Hi everybody, I would like to know if I can put ebeacon parser as a service at startup like starter service (service create or service start) , this means that it is not necessary to have the app open and I can detect the ebeacons, something like ebeacon monitoring in iOS.

Thanks,

Christian
 
Last edited:

freedom2000

Well-Known Member
Licensed User
Longtime User
Hi everybody, I would like to know if I can put ebeacon parser as a service at startup like starter service (service create or service start) , this means that it is not necessary to have the app open and I can detect the ebeacons, something like ebeacon monitoring in iOS.

Thanks,

Christian
Hi,

Yes you can it works in a service
 

Christian García S.

Active Member
Licensed User
Hi,

Yes you can it works in a service

Thanks freedom2000 for you response.

I put:

B4X:
Sub Service_Create
    manager.Initialize("manager")
    beacons.Initialize
'    Timer1.Initialize("timer1", TIME_TO_LIVE_SECONDS * DateTime.TicksPerSecond)
'    Timer1.Enabled = True
    Parser.Initialize
    CallSubDelayed(FirebaseMessaging, "SubscribeToTopics")
   
    Globals.IniDB
    Globals.CreateTables
    Globals.vDeviceid = Globals.GetDeviceId
    Log("Device: " & Globals.vDeviceid)       
End Sub

and:

B4X:
Sub Service_Start (StartingIntent As Intent)
    manager.Scan2(Null, True)   
End Sub

But I dont receive information from beacon, can you give more information about where or how I put the code.

Thanks for your help

Christian
 

Christian García S.

Active Member
Licensed User
Hello everyone,

I am keep trying about read beacons like a service, but I failed, I dont know how I can do.

And now y have reports from some customers with application block.

I put this code in service -> starter

B4X:
Sub Process_Globals
    Public manager As BleManager2
    Public Parser As BeaconParser

    Public beacons As Map
    Public const TIME_TO_LIVE_SECONDS As Int = 5   
End Sub

Sub Service_Create
    manager.Initialize("manager")
    beacons.Initialize
    Parser.Initialize
   
    Globals.IniDB
    Globals.CreateTables
End Sub

Sub Service_Start (StartingIntent As Intent)
    manager.Scan2(Null, True)
End Sub

Public Sub Scan
    manager.Scan2(Null, True)
    scanning = True
End Sub

I check report in google app developer and I got these errors:

B4X:
java.lang.RuntimeException:
  at anywheresoftware.b4a.objects.BleManager2.Scan2 (BleManager2.java:142)
  at com.creator.app.starter._service_start (starter.java:370)
  at java.lang.reflect.Method.invoke (Native Method)
  at java.lang.reflect.Method.invoke (Method.java:372)
  at anywheresoftware.b4a.BA.raiseEvent2 (BA.java:186)
  at anywheresoftware.b4a.BA.raiseEvent (BA.java:166)
  at com.creator.app.starter.handleStart (starter.java:105)
  at com.creator.app.starter.access$000 (starter.java:8)
  at com.creator.app.starter$1.run (starter.java:70)
  at anywheresoftware.b4a.objects.ServiceHelper$StarterHelper.onStartCommand (ServiceHelper.java:105)
  at com.creator.app.starter.onStartCommand (starter.java:68)
  at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:3958)
  at android.app.ActivityThread.access$2300 (ActivityThread.java:218)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1842)
  at android.os.Handler.dispatchMessage (Handler.java:102)
  at android.os.Looper.loop (Looper.java:145)
  at android.app.ActivityThread.main (ActivityThread.java:7007)
  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:1404)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1199)

And I got this error too:

java.lang.RuntimeException:
at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:3705)
at android.app.ActivityThread.-wrap23 (ActivityThread.java)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1736)
at android.os.Handler.dispatchMessage (Handler.java:102)
at android.os.Looper.loop (Looper.java:154)
at android.app.ActivityThread.main (ActivityThread.java:6682)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1410)
Caused by: java.lang.RuntimeException:
at anywheresoftware.b4a.BA.raiseEvent2 (BA.java:223)
at anywheresoftware.b4a.BA.raiseEvent (BA.java:166)
at com.creator.app.starter.handleStart (starter.java:105)
at com.creator.app.starter.access$000 (starter.java:8)
at com.creator.app.starter$1.run (starter.java:70)
at anywheresoftware.b4a.objects.ServiceHelper$StarterHelper.onStartCommand (ServiceHelper.java:105)
at com.creator.app.starter.onStartCommand (starter.java:68)
at android.app.ActivityThread.handleServiceArgs (ActivityThread.java:3688)

Thanks for your help.
 

Christian García S.

Active Member
Licensed User
Hello everyone,

I have an issue con beacon parser when I have ebeacon and eddystone and the same time, the app crash with this error:

B4X:
Error occurred on line: 115 (Starter)
java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.shell.Shell.runGoodChain(Shell.java:463)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:285)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:249)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:139)
    at anywheresoftware.b4a.BA$2.run(BA.java:360)
    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:6934)
    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:1404)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Caused by: java.lang.ClassCastException: com.company.app.beaconparser$_eddystoneurl cannot be cast to com.company.app.beaconparser$_ibeacon
    at com.company.app.starter._manager_devicefound(starter.java:283)
    ... 17 more
Error occurred on line: 115 (Starter)
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[])' on a null object reference
    at anywheresoftware.b4a.shell.Shell.runGoodChain(Shell.java:463)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:285)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:249)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:139)
    at anywheresoftware.b4a.BA$2.run(BA.java:360)
    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:6934)
    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:1404)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
*** Service (httputils2service) Create ***
** Service (httputils2service) Start **
** Service (httputils2service) Start **
** Service (httputils2service) Start **
** Service (httputils2service) Start **
java.lang.RuntimeException: java.io.EOFException
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:170)
    at anywheresoftware.b4a.BA$2.run(BA.java:360)
    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:6934)
    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:1404)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Caused by: java.io.EOFException
    at java.io.DataInputStream.readByte(DataInputStream.java:77)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:335)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:249)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:139)
    ... 9 more

The app crash because I have Eddystone URL sending at the same time that beacons, when I disable the Eddystone URL app works normally.

I am using Beacon Toy in google play for simulate Eddystone.

I was checking with debug mode and crash in this code from Sub ParseEddystone in class Beacon Parser.

B4X:
Return b(3 - offset) - 41

Afternoon I have an event and I need both type of beacons, and I can't open app, crash immediately.

Thanks for your help.
 
Last edited:

Christian García S.

Active Member
Licensed User
Thanks @Erel,

I have not made any changes to the original code.

Thanks @KMatle

Beacons and Eddystone are recognized immediately, but APP when Eddystone recognizes the URL crash in the code:

B4X:
Return b(3 - offset) - 41

I do not know what you mean about BLE tags.

Thanks

Christian
 
Last edited:

Christian García S.

Active Member
Licensed User
Hello,

I want to buy a Bluetooth printer and connecting with bluetooth admin, I can use Beacon parser and still keep connected (paired) with printer??

I want to know before buy the printer.

Thanks in advance.

Christian
 

Eduardo Enri

Member
Licensed User
Erel, this example is very interesting, but it would be easy to update it to use the recent xCustomListView instead of the old CustomListView ?.

Thanks in advance!
 
Top