Sub Class_Globals
Private VERSION As String = "rBLEServer Example BLETCPBridge v20250302"
Private Root As B4XView
Private xui As XUI
Private LabelBLEState As B4XView
Private LabelTemperature As B4XView
Private LabelHumidity As B4XView
Private LabelInterval As B4XView
Private CustomListViewLog As CustomListView
Private ButtonReconnect As B4XView
Private B4XSeekBarInterval As B4XSeekBar
Private LabelSeekBarIntervalValue As B4XView
Private ButtonIntervalSet As B4XView
Private CheckBoxLED As B4XView
Private Shl As Shell
Private BLE_TCP_BRIDGE_SCRIPT As String = "bletcpbridge.py"
Private CMD_STOP As String = "stop"
Private ClientSocket As Socket
Private AStream As AsyncStreams
Private SERVER_IP As String = "127.0.0.1"
Private SERVER_PORT As Int = 58001
Private bc As ByteConverter
End Sub
Public Sub Initialize
B4XPages.GetManager.LogEvents = True
End Sub
Private Sub B4XPage_Created (Root1 As B4XView)
Root = Root1
Root.LoadLayout("MainPage")
B4XPages.SetTitle(Me, VERSION)
LabelBLEState.Text = "Disconnected"
ButtonReconnect.Enabled = True
CheckBoxLED.Enabled = False
RunPythonScript($"${BLE_TCP_BRIDGE_SCRIPT}"$)
ClientSocket.Initialize("ClientSocket")
'ClientSocket_Connect is called in the Shell event StdErr after the bridge connects to the ESP32 via BLE
End Sub
Private Sub B4XPage_CloseRequest As ResumableSub
Dim command() As Byte = CMD_STOP.GetBytes("UTF8")
AStream_Write(command)
Sleep(100)
Return True
End Sub
Private Sub B4XPage_Background
'NOT USED
End Sub
Private Sub ButtonReconnect_Click
If Not(ClientSocket.Connected) Then
ClientSocket_Connect
End If
End Sub
Private Sub CheckBoxLED_CheckedChange(Checked As Boolean)
SetLED(Checked)
End Sub
Private Sub SetLED(state As Boolean)
Dim command() As Byte = IIf(state, Array As Byte(0x01, 0x01), Array As Byte(0x01, 0x00) )
If ClientSocket.Connected Then
AStream_Write(command)
CustomListViewLog_Insert($"${DateTime.time(DateTime.now)} :: Set LED state to ${IIf(state,"ON","OFF")}"$)
End If
End Sub
Private Sub ButtonIntervalSet_Click
Dim command(2) As Byte
command(0) = 0x04
command(1) = IntToByte(B4XSeekBarInterval.Value)
If ClientSocket.Connected Then
AStream_Write(command)
CustomListViewLog_Insert($"[B4XSeekBarInterval_ValueChanged] value=${B4XSeekBarInterval.Value}, hex=${bc.HexFromBytes(command)}"$)
End If
End Sub
Private Sub B4XSeekBarInterval_ValueChanged (Value As Int)
LabelSeekBarIntervalValue.Text = $"${Value} s."$
End Sub
Private Sub CustomListViewLog_Insert(item As String)
CustomListViewLog.InsertAt(0, CustomListViewLog_CreateItem(item), "")
'CustomListViewLog.Add(CustomListViewLog_CreateItem(item), "")
End Sub
Sub CustomListViewLog_CreateItem(item As String) As Pane
Dim pnl As B4XView = xui.CreatePanel("")
pnl.Color = xui.Color_White
pnl.SetLayoutAnimated(0, 0, 0, CustomListViewLog.AsView.Width, 30dip)
Dim lbl As B4XView = XUIViewsUtils.CreateLabel
lbl.Text = item
lbl.SetTextAlignment("CENTER", "LEFT")
lbl.Font = xui.CreateDefaultBoldFont(14)
pnl.AddView(lbl, 0, 0, CustomListViewLog.AsView.Width, 30dip)
Return pnl
End Sub
Public Sub RunPythonScript(script As String)
Shl.Initialize("shl", "python", Array(script))
Shl.WorkingDirectory = File.DirApp
Shl.RunWithOutputEvents(-1)
CustomListViewLog_Insert($"[BLE-TCP-Bridge] Waiting for BLE connection"$)
End Sub
Sub shl_ProcessCompleted (Success As Boolean, ExitCode As Int, StdOut As String, StdErr As String)
Log($"[shl_ProcessCompleted] Success=${Success}, ExitCode=${ExitCode}, StdOut=${StdOut}, StdErr=${StdErr}"$)
End Sub
Sub shl_StdOut (Buffer() As Byte, Length As Int)
Dim j As JSONParser
Try
j.Initialize(BytesToString(Buffer, 0, Length, "UTF8"))
Dim m As Map = j.NextObject
If m.Get("event") == "connect" Then
Dim status As Int = m.Get("status")
If status == 1 Then
ClientSocket_Connect
End If
End If
Catch
Log($"[Stdout][INFO]${LastException}"$)
End Try
End Sub
Sub shl_StdErr (Buffer() As Byte, Length As Int)
'TODO: Improve error handling
End Sub
Sub ClientSocket_Connect
Dim statemsg As String
ClientSocket.Connect(SERVER_IP, SERVER_PORT, 0)
Wait For (ClientSocket) ClientSocket_Connected (Successful As Boolean)
If Successful Then
AStream.Initialize(ClientSocket.InputStream, ClientSocket.OutputStream, "AStream")
End If
statemsg = IIf(Successful, "Connected", "Disconnected")
CallSubDelayed2(Me, "SetLabelBLEState", statemsg)
CheckBoxLED.Enabled = ClientSocket.connected
Log($"[ClientSocket_Connect] ${statemsg}"$)
End Sub
Sub SetLabelBLEState(msg As String)
LabelBLEState.Text = msg
End Sub
'Sub ClientSocket_Connected (Successful As Boolean)
'NOT NEEDED because using wait for in connect
'End Sub
Sub AStream_NewData( Buffer() As Byte )
Dim temperature As Float = IntFromBytes(Buffer(1),Buffer(0)) / 100
Dim humidity As Float = IntFromBytes(Buffer(3),Buffer(2)) / 100
Dim interval As Short = IntFromBytes(Buffer(5),Buffer(4)) / 1000
LabelTemperature.Text = $"${temperature} °C"$
LabelHumidity.Text = $"${humidity} %RH"$
LabelInterval.Text = $"Advertising interval"$
If interval <> B4XSeekBarInterval.Value Then
B4XSeekBarInterval.Value = interval
LabelSeekBarIntervalValue.Text = $"${interval} s"$
End If
CustomListViewLog_Insert($"${DateTime.time(DateTime.now)} :: ${temperature} °C, ${humidity} %RH, ${interval} s"$)
End Sub
Sub AStream_Write(command() As Byte)
If ClientSocket.Connected Then
AStream.Write(command)
End If
End Sub
Sub AStream_Error
Log("[AStream_Error] " & LastException.Message )
End Sub
Sub AStream_Terminated
Log("[AStream_Terminated]")
End Sub
Public Sub PrintMap(m As Map)
For Each key As String In m.Keys
Dim value As String = m.Get(key)
Log($"key: ${key}, value: ${value}"$)
Next
End Sub
Public Sub IntFromBytes(b1 As Byte, b2 As Byte) As Int
Dim hex As String = bc.HexFromBytes(Array As Byte(b1,b2))
Dim result As Int = Bit.ParseInt(hex, 16)
'Log($"[IntFromBytes] hex=${hex}, int=${result}"$)
Return result
End Sub
Public Sub IntToByte(value As Int) As Byte
If value >= 0 And value <= 255 Then
Dim result As Byte = value
End If
Return result
End Sub