B4R Question Receive data from ESP32 via BLE (Hire , pay)

Frank new b4a

New Member
Can someone help me to get in b4a the functionality to connect via Ble to an esp32 which is sending values (characteritics) from a distance sensor.
I can get it working with App inventor, but now I want it in B4a.
I tried 10 examples, but none of them seem to work for me. The tutorial example connects to first ble device available, but I want it to choose which one to connect to.
and connections stops after 10 seconds. Also it isn't getting the charateristics value.


These are my service and charateristics in Esp32:
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

This takes me so long , so I am willing to pay for the service.
 

GabrielM

Member
Licensed User
Longtime User
Presuming your ESP32 BLE devices sharing the same advertising name you could add a filter on found devices, like:

Device found:
Sub Manager_DeviceFound (Name As String, Id As String, AdvertisingData As Map, RSSI As Double)
    'Log("Found: " & Name & ", " & Id & ", RSSI = " & RSSI & ", " & AdvertisingData) 
    Dim nm As NameAndMac
    nm.Initialize
    nm.Name = Name
    nm.Mac = Id
    If nm.Name = "yourDeviceAdvertisingName" Then            ' filter heard one by name
        heardDeviceList.Add(nm)                                ' add it to a list
        combineHeardDeviceList.Add(nm.Name & " - "&nm.Mac)    ' and add also the coresponding MAC heard,
                                                            ' so you can differentiate later
    End If
End Sub

Now, what I do is using a timer for the scan timeout, so I can choose which BLE device I want to connect to from the list above


timer:
' declare a timer
Dim scanTimeout As Timer

' initialize the timer
Public Sub Initialize
    '...
    scanTimeout.Initialize("scanTimeout", 3000)    ' arbitrary 3 seconds period
    '...
End Sub

' enable the timer on a Scan Start
Public Sub StartScan
    If manager.State <> manager.STATE_POWERED_ON Then
        Log("Not powered on.")
    Else
        Log("Start SCanning")
        scanTimeout.Enabled = True    ' start this timer
        manager.Scan2( Null, False)    ' don't allow duplicates
    End If
End Sub

And when the Timer triggers this sub gets called, which in turn allows you to choose and connect to the respective BLE device


scantimeout:
private Sub scanTimeout_Tick
    manager.StopScan                        ' say we heard'em all, can stop scanning for now
    StateChanged
    scanTimeout.Enabled = False                ' and stop this timer
    
    If connected = False Then
        InputListAsync(combineHeardDeviceList, "Choose device to connect", -1, True)    ' show list and choose device
        Wait For InputList_Result (Index As Int)
        If Index <> DialogResponse.CANCEL Then
            Dim device As NameAndMac
            device.Initialize
            device = heardDeviceList.Get(Index)
            ConnectedName = device.Name                ' connected BLE device Name
            ConnectedID = device.Mac                ' connected BLE MAC address
            Label_Name_Val.Text = ConnectedName        ' here I show values on user UI
            Label_MAC_Val.Text = ConnectedID        '
            'LogColor("connecting to: "&ConnectedName&" - "&ConnectedID, Colors.Green)
            manager.Connect2(device.Mac, False)     ' here you start connecting to chosen device
                                                    ' disabling auto connect can make the connection quicker
            ProgressDialogShow2($"Trying to connect to: ${device.Name} (${device.Mac})"$, False)    ' user UI related
            Sleep(3000)            ' some drama
            ProgressDialogHide
        End If
        '
        heardDeviceList.clear
        combineHeardDeviceList.Clear
    End If
End Sub

As for the Service and Characteristics,
to get the DataAvailable your ESP32 could use Notify or you could read the needed Characteristic with something like: manager.ReadData2(Service, Characteristic)

Here is an example on checking against the standard Info Service, UUID = "0000180a-0000-1000-8000-00805f9b34fb" ,
and for your example defined Service and Characteristic UUID


dataavailable:
' Your Service and Characteristic
Public SERVICE_UUID As String =         "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
Public CHARACTERISTIC_UUID as String =     "beb5483e-36e1-4688-b7f5-ea07361b26a8"


' DEVICE INFORMATION SERVICE
Public INFO_SERVICE_UUID As String =     "0000180a-0000-1000-8000-00805f9b34fb"
'         INFORMATION SERVICE characteristics
Public MODEL_NUMBER As String =         "00002a24-0000-1000-8000-00805f9b34fb"        ' Model Number String
Public SERIAL_NUMBER As String =         "00002a25-0000-1000-8000-00805f9b34fb"         '     Serial Number String
Public FIRMWARE_REVISION As String =     "00002a26-0000-1000-8000-00805f9b34fb"         '     Firmware Revision String
Public HARDWARE_REVISION As String =     "00002a27-0000-1000-8000-00805f9b34fb"         '     Software Revision String
Public SOFTWARE_REVISION As String =     "00002a28-0000-1000-8000-00805f9b34fb"         '     Software Revision String
Public MANUFACTURER As String =            "00002a29-0000-1000-8000-00805f9b34fb"         ' Manufacturer Name String


Sub Manager_DataAvailable (ServiceId As String, Characteristics As Map)
    Dim bc As ByteConverter
'    Log("+++++++++++++++++++++++++++++++++++++++++")
'    Log("sid = "&ServiceId)
'    LogColor("characteristics size = "&Characteristics.Size, Colors.yellow)
    If ServiceId = INFO_SERVICE_UUID Then                ' check if it is a InfoService UUID
        For Each id As String In Characteristics.Keys
            Dim dataContent() As Byte = Characteristics.Get(id)
            Select id
                Case MODEL_NUMBER
                    conModelNumber = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("Model: " & conModelNumber)
                Case SERIAL_NUMBER
                    conSerialNumber = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("Serial no.: " & conSerialNumber)
                Case FIRMWARE_REVISION
                    conFirmwareRevision = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("FW rev: " & conFirmwareRevision)
                Case HARDWARE_REVISION
                    conHardwareRevision = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("HW rev: " & conHardwareRevision)
                Case SOFTWARE_REVISION
                    conSoftwareRevision = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("SW rev: " & conSoftwareRevision)
                Case MANUFACTURER
                    conManufacturerName = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("Manufacturer: " & conManufacturerName)
            End Select
            ' update some labels on UI
            Label_Model_Val.Text = conModelNumber
            Label_SerialNo_Val.Text = conSerialNumber
            Label_Firmware_Val.Text = conFirmwareRevision
            Label_Hardware_Val.Text = conHardwareRevision
            Label_Software_Val.Text = conSoftwareRevision
            Label_Manufacturer_Val.Text = conManufacturerName
        Next
    End If
    
    
    If ServiceId = SERVICE_UUID Then                                ' check if it your Service UUID
        If Characteristics.ContainsKey(CHARACTERISTIC_UUID) Then    ' and if Characteristic is the one you're after
            If Characteristics.Getvalueat(0)<>Null Then
                'LogColor("Got my Service and Characteristic UUID I was after ...", Colors.blue)
                Dim b() As Byte = Characteristics.Getvalueat(0)        ' here you can get the Characteristic data and an array
                                                                    ' for further processing ...
                '...
                End If
            End If
        End If
    End If

End Sub


Cheers
 
Upvote 0

emexes

Expert
Licensed User
Can someone help me to get in b4a the functionality to connect via Ble to an esp32 which is sending values (characteristics) from a distance sensor.
BLE nRF Connect pre-BLE2 problem solving
it's always nice to know that everything else in the chain *is* working, and that there is a fighting chance of victory. šŸ†

Can nRF Connect on the same Android phone read your distance data from the ESP32?
 
Last edited:
Upvote 0

Frank new b4a

New Member
Presuming your ESP32 BLE devices sharing the same advertising name you could add a filter on found devices, like:

Device found:
Sub Manager_DeviceFound (Name As String, Id As String, AdvertisingData As Map, RSSI As Double)
    'Log("Found: " & Name & ", " & Id & ", RSSI = " & RSSI & ", " & AdvertisingData)
    Dim nm As NameAndMac
    nm.Initialize
    nm.Name = Name
    nm.Mac = Id
    If nm.Name = "yourDeviceAdvertisingName" Then            ' filter heard one by name
        heardDeviceList.Add(nm)                                ' add it to a list
        combineHeardDeviceList.Add(nm.Name & " - "&nm.Mac)    ' and add also the coresponding MAC heard,
                                                            ' so you can differentiate later
    End If
End Sub

Now, what I do is using a timer for the scan timeout, so I can choose which BLE device I want to connect to from the list above


timer:
' declare a timer
Dim scanTimeout As Timer

' initialize the timer
Public Sub Initialize
    '...
    scanTimeout.Initialize("scanTimeout", 3000)    ' arbitrary 3 seconds period
    '...
End Sub

' enable the timer on a Scan Start
Public Sub StartScan
    If manager.State <> manager.STATE_POWERED_ON Then
        Log("Not powered on.")
    Else
        Log("Start SCanning")
        scanTimeout.Enabled = True    ' start this timer
        manager.Scan2( Null, False)    ' don't allow duplicates
    End If
End Sub

And when the Timer triggers this sub gets called, which in turn allows you to choose and connect to the respective BLE device


scantimeout:
private Sub scanTimeout_Tick
    manager.StopScan                        ' say we heard'em all, can stop scanning for now
    StateChanged
    scanTimeout.Enabled = False                ' and stop this timer
   
    If connected = False Then
        InputListAsync(combineHeardDeviceList, "Choose device to connect", -1, True)    ' show list and choose device
        Wait For InputList_Result (Index As Int)
        If Index <> DialogResponse.CANCEL Then
            Dim device As NameAndMac
            device.Initialize
            device = heardDeviceList.Get(Index)
            ConnectedName = device.Name                ' connected BLE device Name
            ConnectedID = device.Mac                ' connected BLE MAC address
            Label_Name_Val.Text = ConnectedName        ' here I show values on user UI
            Label_MAC_Val.Text = ConnectedID        '
            'LogColor("connecting to: "&ConnectedName&" - "&ConnectedID, Colors.Green)
            manager.Connect2(device.Mac, False)     ' here you start connecting to chosen device
                                                    ' disabling auto connect can make the connection quicker
            ProgressDialogShow2($"Trying to connect to: ${device.Name} (${device.Mac})"$, False)    ' user UI related
            Sleep(3000)            ' some drama
            ProgressDialogHide
        End If
        '
        heardDeviceList.clear
        combineHeardDeviceList.Clear
    End If
End Sub

As for the Service and Characteristics,
to get the DataAvailable your ESP32 could use Notify or you could read the needed Characteristic with something like: manager.ReadData2(Service, Characteristic)

Here is an example on checking against the standard Info Service, UUID = "0000180a-0000-1000-8000-00805f9b34fb" ,
and for your example defined Service and Characteristic UUID


dataavailable:
' Your Service and Characteristic
Public SERVICE_UUID As String =         "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
Public CHARACTERISTIC_UUID as String =     "beb5483e-36e1-4688-b7f5-ea07361b26a8"


' DEVICE INFORMATION SERVICE
Public INFO_SERVICE_UUID As String =     "0000180a-0000-1000-8000-00805f9b34fb"
'         INFORMATION SERVICE characteristics
Public MODEL_NUMBER As String =         "00002a24-0000-1000-8000-00805f9b34fb"        ' Model Number String
Public SERIAL_NUMBER As String =         "00002a25-0000-1000-8000-00805f9b34fb"         '     Serial Number String
Public FIRMWARE_REVISION As String =     "00002a26-0000-1000-8000-00805f9b34fb"         '     Firmware Revision String
Public HARDWARE_REVISION As String =     "00002a27-0000-1000-8000-00805f9b34fb"         '     Software Revision String
Public SOFTWARE_REVISION As String =     "00002a28-0000-1000-8000-00805f9b34fb"         '     Software Revision String
Public MANUFACTURER As String =            "00002a29-0000-1000-8000-00805f9b34fb"         ' Manufacturer Name String


Sub Manager_DataAvailable (ServiceId As String, Characteristics As Map)
    Dim bc As ByteConverter
'    Log("+++++++++++++++++++++++++++++++++++++++++")
'    Log("sid = "&ServiceId)
'    LogColor("characteristics size = "&Characteristics.Size, Colors.yellow)
    If ServiceId = INFO_SERVICE_UUID Then                ' check if it is a InfoService UUID
        For Each id As String In Characteristics.Keys
            Dim dataContent() As Byte = Characteristics.Get(id)
            Select id
                Case MODEL_NUMBER
                    conModelNumber = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("Model: " & conModelNumber)
                Case SERIAL_NUMBER
                    conSerialNumber = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("Serial no.: " & conSerialNumber)
                Case FIRMWARE_REVISION
                    conFirmwareRevision = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("FW rev: " & conFirmwareRevision)
                Case HARDWARE_REVISION
                    conHardwareRevision = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("HW rev: " & conHardwareRevision)
                Case SOFTWARE_REVISION
                    conSoftwareRevision = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("SW rev: " & conSoftwareRevision)
                Case MANUFACTURER
                    conManufacturerName = BytesToString(dataContent, 0, dataContent.Length, "UTF8")
                    Log("Manufacturer: " & conManufacturerName)
            End Select
            ' update some labels on UI
            Label_Model_Val.Text = conModelNumber
            Label_SerialNo_Val.Text = conSerialNumber
            Label_Firmware_Val.Text = conFirmwareRevision
            Label_Hardware_Val.Text = conHardwareRevision
            Label_Software_Val.Text = conSoftwareRevision
            Label_Manufacturer_Val.Text = conManufacturerName
        Next
    End If
   
   
    If ServiceId = SERVICE_UUID Then                                ' check if it your Service UUID
        If Characteristics.ContainsKey(CHARACTERISTIC_UUID) Then    ' and if Characteristic is the one you're after
            If Characteristics.Getvalueat(0)<>Null Then
                'LogColor("Got my Service and Characteristic UUID I was after ...", Colors.blue)
                Dim b() As Byte = Characteristics.Getvalueat(0)        ' here you can get the Characteristic data and an array
                                                                    ' for further processing ...
                '...
                End If
            End If
        End If
    End If

End Sub


Cheers
Hi Gabriel,
Thanks a lot for help :). I am very new to B4A. I have some visual basic experience. I am not sure where to start with the code you send me. Can I add that to the standard BLE 2 example? Or is there a working example with your code somewhere?

Regards,
Frank
 
Upvote 0

GabrielM

Member
Licensed User
Longtime User
Hi Gabriel,
Thanks a lot for help :). I am very new to B4A. I have some visual basic experience. I am not sure where to start with the code you send me. Can I add that to the standard BLE 2 example? Or is there a working example with your code somewhere?

Regards,
Frank
Hello Frank
For starters try @emexes advice above, make sure your BLE device performs as expected. If possible, post some relevant screenshots of a nRF Connect session on that BLE device you are using.

Try start with this code,it is based on the standard BLE2 example, with some parts of it replaced/modified, to accommodate the above snippets. The original code of the example is still in there, thought that might be of any help.

Looking forward to see some progressing piece of code of yours on the subject.
Cheers
 

Attachments

  • BLEExample-01.zip
    16.3 KB · Views: 97
Upvote 0

Frank new b4a

New Member
I know for sure that ESP32 is working . I have MIT app inventor app where I can read the values. I tried the code of Gabriel, I can choose my device. It connects, but if I press the read button it shows the 3 red dots, but not the values.
 
Upvote 0

Comalco

Member
Licensed User
Longtime User
I know for sure that ESP32 is working . I have MIT app inventor app where I can read the values. I tried the code of Gabriel, I can choose my device. It connects, but if I press the read button it shows the 3 red dots, but not the values.
Hi Frank,
Could you please share your AppInventor file that works reading the ESP32 BLE? I have had an unending problem getting an AppInventor app to connect to my ESP32 using BLE. I am really curious what you're doing to get something working, as there are several threads on the webs explaining similar issues to what I have been experiencing. TIA.
 
Upvote 0
Top