B4A Library [B4X] BLE 2 - Bluetooth Low Energy

Status
Not open for further replies.
This library replaces the previous BLE library.
It is simpler to use and it is more powerful. Its API is based on B4i iBLE library which makes it easy to reuse B4i code.

See the iBLE tutorial: https://www.b4x.com/android/forum/threads/ble-bluetooth-low-energy-library.46099/#content

Tips & Notes

- You can call Manager.Scan2 with AllowDuplicates set to True if you want to monitor the state of an unconnected device.
- The AdvertisingData map in DeviceFound event holds pairs of integers as keys (data types) and bytes arrays as values.
- Call ReadData2 if you are only interested in a single characteristic.
- BLE is only supported on Android 4.3+.

See the attached example. Note that the important code in in the Starter service module.

Edit:

A new version of BLE_Example was uploaded. targetSdkVersion is now set to 29
Setting the targetSdkVersion to 29 requires some changes:

1. Add the fine location permission in the manifest editor.
2. Request this permission with RuntimePermissions.

Otherwise scanning will fail with a message visible in the unfiltered logs.

BLE2 is an internal library now. It is included in the IDE.

Example is based on B4XPages and will work with B4A and B4i.

Updates:
- Example updated with targetSdkVersion = 31. Note the permissions in the manifest editor:
B4X:
AddPermission(android.permission.ACCESS_FINE_LOCATION)
AddPermission(android.permission.BLUETOOTH_SCAN)
AddPermission(android.permission.BLUETOOTH_CONNECT)
And requesting at runtime:
B4X:
Dim Permissions As List
Dim phone As Phone
If phone.SdkVersion >= 31 Then
    Permissions = Array("android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT", rp.PERMISSION_ACCESS_FINE_LOCATION)
Else
    Permissions = Array(rp.PERMISSION_ACCESS_FINE_LOCATION)
End If
For Each per As String In Permissions
    rp.CheckAndRequest(per)
    Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
    If Result = False Then
        ToastMessageShow("No permission: " & Permission, True)
        Return
    End If
Next
 

Attachments

  • BLEExample.zip
    181.6 KB · Views: 2,004
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User

Turbo3

Active Member
Licensed User
Longtime User
I really need to be able to disable retries and handle them in my code if and when they are needed.

The fact that the automatic retries are capable of hanging the foreground process is a no-go for me. It is just too dangerous to have enabled. Not being able to exit my app because auto retry has taken over is not something I ever expected.

Can you say a little more then "retries are important" or is it some how proprietary?

Are you doing auto retry in the iOS version of BLE which has given me no problems. The iOS version of my app has been released for many months now with no problems from any of my many users using the same device I am testing with the Android version.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Can you say a little more then "retries are important" or is it some how proprietary?
There are cases where writings will fail which are difficult to handle outside of the library. The writings do succeed after another attempt or two (and a short delay). This can happen for example if the BLE adapter is busy with a different task.

All of this is not relevant to B4i as it is taken care in a lower level.

As I wrote, I can make this feature optional in the future. However you should first try to manage the writings and make sure that you only call Write after the previous one completed.
 

Turbo3

Active Member
Licensed User
Longtime User
Thanks for the explanation. I appreciate you taking the time to answer my questions.

I have added a simple OkToSend flag that gets set to false after a WriteData and set to true when the WriteComplete event is received. A WriteData is skipped if the OkToSend flag is false. Seem to work with my limited testing tonight. Will test some more tomorrow. The only issue is if the WriteComplete does not happen. I do have a hang timer running so I could set the flag to true in there if needed.

But even with this I would rather have the option to disable the auto retry as my device is always available so no need for the auto retry function.

My app is always trying to connect. This means connections might start at the far limits of the BTLE range so the connection might not be a solid connection and come and go. So the stream of data is hard to predict.
 

Krammig

Member
Licensed User
Longtime User
I have two Bluetooth devices here and have tried to use the BLE Example app to detect them. However not having much luck. Each device has it's own Eclipse style demo program and they work fine.

What I am seeing here on the phone is

BLE State: POWERED ON

The Scan & Connect button is active, and when I press that the Log file reports as follows (see below)
The Disconnect button is never active (per log file I guess)
Status is always Not Connected
Read Data button is never active.

Would appreciate comments
thanks


** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Found: MP100, 8C:DE:52:F1:B6:33, RSSI = -85, (MyMap) {1=[B@2ff21bd4, 9=[B@888a17d, 3=[B@270f0872, 10=[B@302584c3}
Disconnected
Found: MP100, 8C:DE:52:F1:B6:33, RSSI = -88, (MyMap) {1=[B@124139be, 9=[B@c51aa1f, 3=[B@1395116c, 10=[B@274f8335}
Disconnected
** Activity (main) Pause, UserClosed = true **
** Activity (main) Create, isFirst = false **
** Activity (main) Resume **
Found: Suppay_161510, 74:F8:DB:7D:20:FC, RSSI = -50, (MyMap) {1=[B@338c6eb, 2=[B@308a7c48, 10=[B@4850ae1, 9=[B@fc6006}
Disconnected
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
BLE2 v1.35 is attached to the first post. It allows reading the RSSI value of a connected device.
You need to call Manager.ReadRemoteRssi and handle the RssiAvailable event.
B4X:
Sub Manager_RssiAvailable (Success As Boolean, RSSI As Double)
   Log(Success)
   Log(RSSI)
End Sub
 
Last edited:

Juan Carlos López

New Member
Licensed User
Longtime User
Hello

I'm working with the RN4020 module, as host-less.
I have defined one private service with 4 characteristics.
When I list the services with the LS command with Teraterm, it lists these:

11223344556677889900AABBCCDDEEFF
AA0203040506070809000A0B0C0D0E0F,0018,06,02
BB0203040506070809000A0B0C0D0E0F,001A,06,02
CC0203040506070809000A0B0C0D0E0F,001C,06,02
DD0203040506070809000A0B0C0D0E0F,001E,06,08

On my B4A app, I'm reading the services with this code using the BLE2 library: (from an example I have find somewhere)

Sub ble_Connected (Services As Map)
Dim i,j As Int
If ConnectState=cstatePreConnect Then
ConnectState = cstateConnect
For i = 0 To Services.Size - 1
s = Services.GetValueAt(i)
For j = 0 To s.GetCharacteristics.Size - 1
c = s.GetCharacteristics.GetValueAt(j)
Next
Next
PrivServ = Services.GetValueAt(3)
Fabierto = PrivServ.GetCharacteristics.GetValueAt(0)
Fcerrado = PrivServ.GetCharacteristics.GetValueAt(1)
Motor = PrivServ.GetCharacteristics.GetValueAt(2)
Dispositivo = PrivServ.GetCharacteristics.GetValueAt(3)
End If
End Sub

Am I using the characteristic enumeration correctly?
How can I read each characteristic value? It seems I'm using it on the wrong way.

Thank you for your comments.

Juan Carlos.
 

kompiler

Member
Licensed User
Longtime User
I have problem with BLE2 library and Arduino Bluno form DFRoot
https://www.dfrobot.com/wiki/index.php/Bluno_SKU:DFR0267

DF Robot Service: 0000dfb0-0000-1000-8000-00805f9b34fb
DF Robot Characteristics: 0000dfb1-0000-1000-8000-00805f9b34fb

when I try SetIndication

B4X:
ServiceId = "0000dfb0-0000-1000-8000-00805f9b34fb"
ReadChar = "0000dfb1-0000-1000-8000-00805f9b34fb"

Private Sub Manager_Connected (Services As List)
    manager.SetIndication(ServiceId,ReadChar,True)
End Sub

in log

starter_manager_connected (java line: 144)
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.bluetooth.BluetoothGattDescriptor.setValue(byte[])' on a null object reference
at anywheresoftware.b4a.objects.BleManager2.setNotify(BleManager2.java:305)
at anywheresoftware.b4a.objects.BleManager2.SetNotify(BleManager2.java:295)
at b4a.example.starter._manager_connected(starter.java:144)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
at anywheresoftware.b4a.BA$2.run(BA.java:328)
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:6126)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)


Bluno sends one character every second

Please help
 

deantangNYP

Active Member
Licensed User
Longtime User
How come there is no "write" example in the sample code , BLE_Example.zip ? Or did i miss it. Thanks

I'm not familiar with BleExtEx implementation. BLE (the protocol) doesn't support streaming. BLE2 library exposes all the relevant APIs. You can read and write to the BLE peripheral.
 

Angel Maza

Member
Licensed User
Longtime User
Hi

Have you seen slower connection in BLE2 library??. In my app, BLE library connect is in 1-3 secs. With BLE2 depends between 3 and 30 seconds, or even not at all connection in some cases (not distance related).

I've seen that scan_stop before connect improves timings, but even with scan_stop the BLE2 connect is far slower than BLE.
 
Status
Not open for further replies.
Top