Android Tutorial [B4X] MQTT - Connect & Reconnect

Status
Not open for further replies.
The ConnectAndReconnect sub takes care of connecting to the broker and reconnecting if the connection has broken.
It sends a "ping" request every 5 seconds to help the MQTT client recognize network failures.

It is a nice example of how Wait For and Sleep can help to manage the network state which is completely asynchronous.
The ConnectAndReconnect sub will keep running until you set the working variable to False.

B4X:
Sub ConnectAndReconnect
   Do While working
     If mqtt.IsInitialized Then mqtt.Close
       Do While mqtt.IsInitialized
            Sleep(100)
        Loop
     mqtt.Initialize("mqtt", "ssl://io.adafruit.com:8883", "B4X" & Rnd(0, 999999999))
     Dim mo As MqttConnectOptions
     mo.Initialize(username, password)
     Log("Trying to connect")
     mqtt.Connect2(mo)
     Wait For Mqtt_Connected (Success As Boolean)
     If Success Then
       Log("Mqtt connected")
       Do While working And mqtt.Connected
         mqtt.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

In B4A it is recommended to put it in the starter service:
B4X:
Sub Process_Globals
   Private working As Boolean = True
   Private mqtt As MqttClient
End Sub

Sub Service_Create
   working = True
   ConnectAndReconnect
End Sub

It is recommended to use B4XPages and call it from B4XPage_Created.


Set working to False before you close the connection.
Make sure to only call this code once.

This code is compatible with B4A, B4i and B4J.
 
Last edited:

janderkan

Active Member
Licensed User
Info

If you set a LastWill then you should not use RND() in the initialize command.

If phone disconnects and reconnects, then the LastWill will be sent after 1 minute, even if the phone is connected again.

Use something unique like MAC address and the LastWill will only be sent if the phone is disconnected.
 

avalle

Active Member
Licensed User
I'm not clear if using this means that the code in existing sub

B4X:
Private Sub Mqtt_Connected (Success As Boolean)

in the Starter service should now be moved to Sub ConnectAndReconnect after

B4X:
Wait For Mqtt_Connected (Success As Boolean)

Specifically I'm trying to make this work with the MQTT Chat and I'm not sure I'm doing it right.

Thanks
Andrea
 

Johan Hormaza

Well-Known Member
Licensed User
B4X:
    Wait For mqtt_Connected (Success As Boolean)
    If Success Then
        Log("Connect")
    Else
        Log("Fail connection")
    End If

so is
 

amorosik

Well-Known Member
Licensed User
I hope you have the patience to explain to me, because I don't understand how the above routine works
Once the connection to the mqtt broker has occurred, the routine ends, right?
And so in case the connection between the program and the mqtt broker is interrupted, who is it that restores it?
 

José J. Aguilar

Expert
Licensed User
Once the connection to the mqtt broker has occurred, the routine ends, right?
When the connection has ocurred, the routine stays sending a "ping" every 5000ms.

B4X:
       Do While working And mqtt.Connected
         mqtt.Publish2("ping", Array As Byte(0), 1, False) 'change the ping topic as needed
         Sleep(5000)
       Loop

And so in case the connection between the program and the mqtt broker is interrupted, who is it that restores it?
If it's interrupted, then mqtt.Connected is false, but working is still true, so the loop reconnect again...

B4X:
   Do While working
     If mqtt.IsInitialized Then mqtt.Close
     mqtt.Initialize("mqtt", "ssl://io.adafruit.com:8883", "B4X" & Rnd(0, 999999999))
     Dim mo As MqttConnectOptions
     mo.Initialize(username, password)
     Log("Trying to connect")
     mqtt.Connect2(mo)
     .......
 
Last edited:

amorosik

Well-Known Member
Licensed User
When the connectios has ocurred, the routine stays sending a "ping" every 5000ms.

B4X:
       Do While working And mqtt.Connected
         mqtt.Publish2("ping", Array As Byte(0), 1, False) 'change the ping topic as needed
         Sleep(5000)
       Loop


If it's interrupted, then mqtt.Connected is false, but working is still true, so the loop reconnect again...

B4X:
   Do While working
     If mqtt.IsInitialized Then mqtt.Close
     mqtt.Initialize("mqtt", "ssl://io.adafruit.com:8883", "B4X" & Rnd(0, 999999999))
     Dim mo As MqttConnectOptions
     mo.Initialize(username, password)
     Log("Trying to connect")
     mqtt.Connect2(mo)
     .......


Many thanks for the clear explanation
So once that routine is launched, the code runs indefinitely, correct?
Only way out when 'working' becomes false

Finally, if I wanted to use this routine to keep an mqtt connection active, but only in rx mode, can i replace the line

mqtt.Publish2 ("ping", Array As Byte (0), 1, False)

with a

mqtt.Subscribe ("My_Topic", 0)

or the line with the write (mqtt.Publish2 ("My_Topic", Array As Byte (0), 1, False) ), MUST remain?
 

José J. Aguilar

Expert
Licensed User
So once that routine is launched, the code runs indefinitely, correct?
Right, while the app is foreground.

but only in rx mode
I think there's no such thing in MQTT. You just subscribe the topic once, and while the client is connected, it will receive any message with that topic (it could be said it will be in rx mode). You just send the "ping" topic to keep the connection alive, and you will receive any message while you're connected, you don't need to subscribe every time.

MUST remain?
Yes, just subscribe once, but send some dummy message to keep the connection alive.
 

José J. Aguilar

Expert
Licensed User
I mean, for obtain an mqtt 'unbreakable' connection also when app is in background?
You should implement it in a background service. You can adapt this example.

But probably is a best option implement a Firebase Notification, and when you get some notify, start your app and connect.

I think it's better you start a new thread.
 

viriato

Member
Licensed User
Hi,
I checked for B4J and it works too Great..

Do you have the same example for B4R , ESP32 ? (may be wrong place to ask.. sorry)

Thanks
 

viriato

Member
Licensed User
Hi Erel,
Thanks ,

I am using this example as a starting point and I added a Timer to blink a LED , publish the ESP32 internal temperature and also detect PIN change state , example attached
But I have an issue with scenario 3 when disconnecting the MQTT broker , timer is not working anymore every and the pin event is not working either (kind of time occurs about every 40 seconds)

1- Program start and everything is connected - OK works fine
2- Program running disconnect network , router (Wi-Fi) - "Disconnected" , "Trying to connect again", TIMER and PIN Change state - OK, Work Fine during the reconnect process , then connect router network - program reconnect again everything works fine
3 - Program running everything OK, disconnect MQTT Broker - "Disconnected" , "Trying to connect again" , TIMER is blocked and trigger ~ 40secondes after and PIN Change state is not active also detected ~40 after switch pushed then connect MQTT Broker - program reconnect again everything works fine.

Any idea about what is wrong ? Any suggestion to make it working ?



Thanks a lot
 

Attachments

  • TEST-CR.zip
    1.7 KB · Views: 12

amorosik

Well-Known Member
Licensed User
I am trying to use the ConnectAndReconnect routine on my app
I have a service module called Mqtt which contains the code used by the app when it has to communicate with the outside world
I entered the Sub ConnectAndReconnect exactly as shown in the first post
From module service Starter / Service_Create I called the relative code initialization routine using
CallSubDelayed (Mqtt, "SubscribeToTopics")
Inside the Mqtt / SubscibeToTopics i inserted the line for the mqtt connection, and then ConnectAndReconnect
When the app starts, the connection is successful, then if I turn off the mqtt broker the connection is interrupted
But if i turn on the mqtt broker the connection does NOT automatically restart
To understand if the connection is active or not, I added a timer to 1 second and inside I print on log mqtt_client.connected
Tested in both debug and release mode
What can I check?

Starter:
Sub Service_Create
    CallSubDelayed(Mqtt,"SubscribeToTopics")
End Sub

Mqtt:
Sub Process_Globals
    Private mqtt_client As MqttClient
    Private serializator As B4XSerializator
    Private mqtt_uri As String
    Private mqtt_name As String
    Public mqtt_connected As Boolean
    Public flag_mqtt_connesso As Boolean=True
    Type Mqtt_Message (Body As String, From As String)
    End Sub

Public Sub SubscribeToTopics
    flag_mqtt_connesso=True
    ConnectAndReconnect
    End Sub

Sub ConnectAndReconnect
    mqtt_uri="http://1.2.3.4:63309"
    mqtt_name="123456789"
    
    Do While flag_mqtt_connesso
        If mqtt_client.IsInitialized Then mqtt_client.Close
        Do While mqtt_client.IsInitialized
            Sleep(100)
            Loop
        mqtt_client.Initialize("EventMqtt", mqtt_uri, mqtt_name)
        Dim mo As MqttConnectOptions
        mo.Initialize("", "")
        mo.SetLastWill("smartphone/sconnesso" , serializator.ConvertObjectToBytes(mqtt_name), 0, False)
        Log("Trying to connect")
        mqtt_client.Connect2(mo)
        Wait For mqtt_connected (Success As Boolean)
     
        If Success Then
            Log("Mqtt connected")
            Do While flag_mqtt_connesso And mqtt_client.Connected
                Log ("Ping verso consolle")
                mqtt_client.Publish2("launcher_to_consolle" , Array As Byte(0), 1, False)
                Sleep(5000)
                Loop
            Log("Disconnected")
            Else
            Log("Error connecting.")
            End If
         
        Sleep(5000)
        Loop
    End Sub
 
Status
Not open for further replies.
Top