B4J Question How to use 'wait for' in a Mqtt Class

CanguroCode

Active Member
Licensed User
I have a mqtt class for broker connection, send messages and receive messages.

The logic that I use is:
1. Client publish message to topic: "mytopic"
2. In the other side an Script is subscribed to the topic: "mytopic"
3. As soon as the message is received, the script publishes in: "response"
4. Client receives message and processes in "Sub MyFunction"

Everything works fine (if I follow the typical way), but for clarity of my code I would like to implement the 'wait for' function to stay waiting to receive a message, but my implementation is not correct, I use the following code (obviously it does not work):

MQTT Class

B4X:
'MQTTUtils

Sub Class_Globals
    Private fx As JFX
    Private client As MqttClient
    Private subtop, pubtop As String
    Public connected As Boolean
    Private MQTTUser, MQTTpass As String
    Private working As Boolean = True
End Sub


Public Sub Initialize( usuario As String, password As String, clientID As String)
    MQTTUser = usuario
    MQTTpass = password
    subtop = "response"
    pubtop = "mytopic"
    ConnectAndReconnect(clientID)
End Sub


Public Sub  client_MessageArrived(Topic As String, Payload() As Byte)
    Dim JSON As JSONParser
    Dim content As List
    Dim head As String
   
    If Payload.Length > 0 Then
        JSON.Initialize(BytesToString(Payload,0,Payload.Length,"UTF8"))
        content = JSON.NextArray
        head = content.Get(0)
        If head.Contains("MyString") Then
            Log("Go to MyFunction")
            CallSub2(Main, "MyFunction", content)
         End If
    End If
End Sub


Private Sub ConnectAndReconnect(clientID As String )
    Do While working
        If client.IsInitialized Then client.Close
        client.Initialize("mqtt", "ssl://io.adafruit.com:8883", "B4X" & Rnd(0, 999999999))
        Dim mo As MqttConnectOptions
        mo.Initialize(MQTTUser, MQTTpass)
        Log("Trying to connect")
        client.Connect2(mo)
        Wait For Mqtt_Connected (Success As Boolean)
        If Success Then
            Log("Mqtt connected")
            client.Subscribe(subtop,1)
            Do While working And client.Connected
                client.Publish2("ping", Array As Byte(0), 1, False) 'change the ping topic as needed
                Sleep(5000)
            Loop
            Log("Disconnected")
        Else
            Log("Error connecting.")
        End If
        Sleep(5000)
    Loop
End Sub
   

Private Sub cliente_Disconnected
    connected = False
End Sub


Public Sub Request(solicitud As String, parametros As String)
    If connected Then
        Log(DateTime.Time(DateTime.Now) & " INFO_MQTTUtils: Publicando Solicitud")
        client.Publish2(pubtop, solicitud.GetBytes("UTF8"),0, False)
    Else
        Log(DateTime.Time(DateTime.Now) & " INFO_MQTTUtils: Publicacion no realizada, cliente no conectado al broker")
    End If
End Sub

Main Code
B4X:
'Main
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Dim mqtt As MQTTUtils
End Sub


Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("principal") 'Load the layout file.
    MainForm.Show
    mqtt.Initialize("usuario1", "1234qweasd")
    mqtt.Request("MyRequest")
    Wait For MyFunction(content as List)
    Log("Process Data from Wait For")
end sub


Sub MyFunction(content as List)
    Log("Process Data from MyFunction")
end sub

What is the right way?
 
Last edited:

CanguroCode

Active Member
Licensed User
I'm Sorry, Mqtt Class edited. Request is a method from my Mqtt Class (MQTTUtils), I want wait for the mqtt MessageArrived or MyFunction (for the example, it's almost the same, I think) after client publish (mqtt.Request)
 

Erel

Administrator
Staff member
Licensed User
All B4X developers must watch this tutorial:
If you want to call a method that sends a request and waits for the response:

B4X:
'in the class
Public Sub SendRequest (data() As Byte) As ResumableSub
 'send the request
 Wait For client_MessageArrived(Topic As String, Payload() As Byte)
 'assuming that you want to return the payload. If you want to return both then use a custom type
 Return Payload
End Sub

'call this sub from main module:
Wait For (MyClass.SendRequest(...)) Complete (Payload() As Byte)
'work with payload
 
Last edited:
Top