MQTT Reconnect
응답
19. 6. 28 오전 9:20

Hey everyone,

I'm trying to automatically reconnect the Wifi Connection and the MQTT connection to the Broker, upon Disconnect from the Wifi, and beeing in range of the Wifi again.

When having a steady connection i get the MQTT Events 15 and 14 (in that order) MQTT_PUBLISHED_DATA => MQTT_INCOMING_PUBLISH

This is the code I use to reconnect to the wifi and afterwards to the MQTT Broker

if(CONNECTED_AND_IPV4_ACQUIRED != WlanConnect_GetCurrentNwStatus()){
    	printf("Wifi NOT connected trying to reconnect\n\r");
    	
        WLAN_Disable();
        Retcode_T retcode = WLAN_Enable();
        if(RETCODE_OK == retcode){
        	printf("WIFI reconnect succesful\n\r");
        } else {
        	printf("WIFI reconnect NOT succesful\n\r");
        }

        // MQTT Reconnect
        retcode = Mqtt_disconnect(SessionPtr);
        if(retcode == RETCODE_OK){
        	printf("MQTT Disconnect succesful\r\n");
        } else {
        	printf("MQTT Disconnect NOT succesful error 0x%04x\r\n", retcode);
        }

        retcode = Mqtt_connect(SessionPtr);
        if(retcode == RETCODE_OK){
        	printf("MQTT Connect succesful\r\n");
        } else {
        	printf("MQTT Connect NOT succesful, error 0x%04x\r\n", retcode);
        }
        if(retcode == RC_MQTT_ALREADY_CONNECTED){
        	printf("MQTT Already Connected!\r\n");
        }

The printouts are that the Wifi reconnect was succesful, the MQTT disconnect was succesful, but the MQTT connect was not succesful and that MQTT is Already Connected.

And following up I only get the MQTT 15 Event: MQTT_PUBLISHED_DATA and not the MQTT 14 Event anymore.

I already tried to change the clientID which registeres at the MQTT Broker, but it still doesnt make a difference.

 

How can i make a automatic reconnect to keep sending Data through MQTT when the Wifi Disconnects for a short/longer time, e.g change of Wifi Access points

 

Thanks in advance for the help.

0 (0 투표)
RE: MQTT Reconnect
응답
19. 7. 2 오후 1:32 as a reply to Martin Scheck.

Hello Martin,

After MQTT session is closed(Mqtt_disconnect()), you need to initiate the session again by calling Mqtt_initialize() method followed by Mqtt_connect().

Please refer the steps necessary for MQTT reconnection in below code snippet. I recommend you to refer MQTT.c for connect function definition.

/* Check WiFi connectivity and make sure it is connected */
/* Check the MQTT connection status */
if (false == Mqtt_isConnected(&MqttSession))
{
         /* Initialize MQTT session */
         Mqtt_initialize();
         Mqtt_initializeInternalSession(&MqttSession);
         /* Configure IP address of the broker URL and other parameters in MqttSession. It is good to request cleanSession. */
         Mqtt_connect(&MqttSession);
}

 

+1 (1 투표)
RE: MQTT Reconnect
응답
19. 7. 3 오전 8:27 as a reply to Padmapriya G.

Hello Padmapriya,

your code snipped helped me a lot in understanding how the connection works.

Following up I am still running in a few errors that i don't come to think of why they occure.

I edited my Mqtt function to match it with your code snippet. And i just call this reconnect function als long as my session is not connected to the Broker anymore, after getting an "MQTT_CONNECTION_CLOSED"

I force the MQTT_CONNECTION_CLOSED by shutting down the Broker and restarting it. Please see below the code I use, and below the results I get.

    case MQTT_CONNECTION_CLOSED:
    	printf("MQTT_CONNECTION_CLOSED, Trying to Reconnect to MQTT Broker\r\n");
    	while(!Mqtt_isConnected(SessionPtr)){
        	vTaskDelay(MQTT_RECONNECT_INTERVALL / portTICK_RATE_MS); //5 sec delay
        	mqttReconnect();

static void mqttReconnect(){
	Retcode_T retcode = RETCODE_OK;
	if(Mqtt_isConnected(SessionPtr)){
		retcode = Mqtt_disconnect(SessionPtr);
		if(retcode == RETCODE_OK){
	    	printf("MQTT Disconnect succesful\r\n");
		} else {
	    	printf("MQTT Disconnect NOT succesful, error 0x%04x\r\n", retcode);
	    	return;
		}
	} else {
		printf("Session not connected\r\n");
	}

	retcode = Mqtt_initialize();
    if(retcode == RETCODE_OK){
    	printf("MQTT initializing succesful\r\n");
    } else {
    	printf("MQTT initializing NOT succesful, error 0x%04x\r\n", retcode);
    	return;
    }

    retcode = Mqtt_initializeInternalSession(SessionPtr);
    if(retcode == RETCODE_OK){
    	printf("MQTT Session initializing succesful\r\n");
    } else {
    	printf("MQTT Session initializing NOT succesful, error 0x%04x\r\n", retcode);
    	return;
    }

    retcode = Mqtt_connect(SessionPtr);
    if(retcode == RETCODE_OK){
    	printf("MQTT connecting succesful\r\n");
    } else {
    	printf("MQTT connecting NOT succesful, error 0x%04x\r\n", retcode);
    }
}

The results is that it succesfully connects to the broker, even though the broker isn't even started yet. Which somehow feels weird that it can connect a session to a broker that is not even live.

Afterwards it says:
MQTT connecting was NOT succesful, error 0x0494

even when the broker is back live.

 

Also when i tried to look into the Mqtt_ping(session) function it seems like it only checks if the session is connected and not if the broker is live and therefore i don't think this helps for my problem.

Furthermore i didn't find anything on clean Session that you recommended, what do you mean by that?

 

Thank you in advance for any help to make a succesful reconnect to the MQTT broker.

Martin


EDIT1: after a few tries a new messag pops up, which seems to be from the syste, itself:

 INFO | XDK DEVICE 3: System Error:, Severity:2 Error code: 65 Package Id:153 and module ID is :63 
 INFO | XDK DEVICE 3:  Reset the system

it says a lot of IDs but where can you look them up?

Even though it says that the System should be reset, the sourcecode keeps executing.

EDIT2: But following up, after the MQTT_CONNECTION_CLOSED event, and the MqttReconnect() Funktion is executed, I get the MQTT_CONNECT_SEND_FAILED event, which calls also the MqttReconnect() function, and now it says that the Sesson is not connected (after the call from MQTT_CONNECTION_CLOSED said it is succesfully connected). And now the program is stuck in the endless loop like above where i call MqttReconnect() as long as it is succesfully reconnected. But it doesn't reconnect even though the Broker beeing back live. And again with the errorcode:

 INFO | XDK DEVICE 3: MQTT connecting NOT succesful, error 0x0494

 

EDIT3: After a few minutes in this loop (while connected to a computer) the devices resets itself and restarts and then everything works fine again. This behaviour but only happenes when its connected to a computer from what i have noticed. Sometimes even the connection to a computer triggers something in the XDK device to start running again if it's stuck. But there has to be somewhat of a workaround since, I cant have a compuert connected to the XDK for the whole time

0 (0 투표)
RE: MQTT Reconnect
응답
19. 7. 3 오전 10:22 as a reply to Martin Scheck.

Hello Martin,

From your post i understand that MQTT_CONNECTION_CLOSED is triggered by manually stopping the broker.

Since the broker is no longer active, you get event MQTT_CONNECTION_CLOSED (when server has not responded to the subscribe message) and send failed event (MQTT_CONNECT_SEND_FAILED). Which is expected.

  • I would like to understand if MQTT connect, publish, subscribe has worked for you once?
  • What is your MQTT broker ?
  • Please check the Mqtt session parameters. Please read MQTT spec for knowing about the session parameters http://mqtt.org/documentation
    • The mqtt broker URL
    •  cleanSession : decides whether you want to persist the previous subscription messages and undelivered messages
    • If you set cleanSession  as true, please make sure to pass correct clientID
    • haveWill

Recommonded mqtt session is

                MqttSession.MQTTVersion = 3;
                MqttSession.keepAliveInterval = 100;
                MqttSession.cleanSession = true;
                MqttSession.will.haveWill = false;
                MqttSession.onMqttEvent = MqttEventHandler;
                MqttSession.clientID = clientID;

Can you share you complete code to inorder to support further.

0 (0 투표)
RE: MQTT Reconnect
응답
19. 7. 4 오전 8:12 as a reply to Padmapriya G.

Hello Padmapriya,

thanks for the quick response.

I use a Mosquito MQTT Broker in Version 1.6.3. And I run MQTT in Version 3.1.1.

Let me trying to explain whats happening in my code with the fitting code snippets.

1. Initializing MQTT.

retcode_t rc_initialize = Mqtt_initialize();

2. Configurating the MQTT Session.

static MqttSession_T *SessionPtr;                
SessionPtr->target.scheme = SERVAL_SCHEME_MQTT;
SessionPtr->onMqttEvent = EventHandler;
SessionPtr->MQTTVersion = 3;
SessionPtr->keepAliveInterval = 100;
SessionPtr->cleanSession = true;
SessionPtr->will.haveWill = false;
SessionPtr->username = username;
SessionPtr->password = password;
SessionPtr->clientID = device_Mac_Address;

3. Connecting to MQTT

retcode_t rc = Mqtt_connect(SessionPtr);

4. Returning i get the MQTT_CONNECTION_ESTABLISHED which i answer with my EventHandler into Subscribing to the Topic

strncpy((char *)topic_buffer, Topics[0].start, sizeof(topic_buffer));
printf("Subscribing to topic: %s, Qos: %d\n\r", topic_buffer, Qos[0]);
retcode_t rc_subscribe = Mqtt_subscribe(SessionPtr, 1, Topics, Qos);

5. In return i get the MQTT_SUBSCRIPTION_ACKNOWLEDGED Event, which i handle with enquing messages and publishing them. In this PublishData function I check if the wifi is still connected (if not i try to reconnect to the Wifi and afterwards to the MQTT Broker) Afterwards i publish my data.

static void PublishData(void *param1, uint32_t param2)
{
    retcode_t rc_publish;
    if(CONNECTED_AND_IPV4_ACQUIRED != WlanConnect_GetCurrentNwStatus()){
    	wlanReconnect();
    	mqttReconnect();
    }
   if(!Mqtt_isConnected(SessionPtr)){
    	mqttReconnect();
    }
    char* httpBodyBuffer =  receiveBufferFromSensors();
    rc_publish = Mqtt_publish(SessionPtr, PublishTopicDescription,httpBodyBuffer, strlen(httpBodyBuffer)+1, (uint8_t) MQTT_QOS_AT_MOST_ONE, false);
    if (rc_publish == RC_OK)
    {
        PublishInProgress = 1;
    }
    else
    {
        PublishInProgress = 0;
        Retcode_RaiseError(RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_MQTT_PUBLISH_FAIL));
    }
    free(httpBodyBuffer);
}

6. Afterwards i get MQTT_PUBLISHED_DATA to set the "PublishInProgress" to 0, MQTT_INCOMING_PUBLISH to then see the published message.

7. Afterwards theres just repeating these Publishing steps.

8. Upon shutting down the Broker, I get MQTT_CONNECTION_FAILED and therfore heading straight to my mqttReconnect() Function

Retcode_T retcode = RETCODE_OK;
retcode = Mqtt_ping(SessionPtr);
    if(Mqtt_isConnected(SessionPtr)){
retcode = Mqtt_disconnect(SessionPtr);
}
retcode = Mqtt_initialize();
retcode = Mqtt_initializeInternalSession(SessionPtr);
retcode = Mqtt_connect(SessionPtr);
retcode = Mqtt_ping(SessionPtr);

In between there are a few print outs that i just left out for a better view. Also the pings are just to verify whats happening.

9. In the first run of this, MQTT initializes succesfully, MQTT Internal Session initializes succesfully, MQTT connects succesfully, and the Ping is succesful.

10. Afterwards i get the MQTT_CONNECT_SEND_FAILED, which i handle with the same mqttReconnect() function. Where the first ping results in a RC_MQTT_NOT_CONNECTED, and also the mqtt_isConnected(SessionPtr) returns false. So again the MQTT initialization succedes also does the MQTT Internal Session and also the MQTT connection succedes again.

11. these last the loop for a bit, sometimes I get MQTT_PING_SEND_FAILED. But after a few retries the processor resets

 INFO | XDK DEVICE 3: HardFault_Occured_going to reset the processor 

12. Afterwards the XDK completely restarts and succesfully reconnects.

 

But it seems like after 8. theres no consistent way on what is happening.

The clientID doesnt change and isn't changed at all and is Unique, due it beeing the XDK device's WLAN MAC Address.

I just noticed that my SessionPtr->MQTTVersion should be 4. But I dont think that should be the difference.

Hopefully this clears up where my problem lies and you may be able to help me out.

Thank you in advance

Martin

0 (0 투표)
RE: MQTT Reconnect
응답
19. 7. 8 오전 9:03 as a reply to Martin Scheck.

Hello Martin,

I have encountered broker disconnection and reconnection again without any issues (without system restart).

I do not see any error event MQTT_CONNECTION_FAILED from Serval Mqtt. Can you please revisit the error code?

Thank you,

Padmapriya

0 (0 투표)
RE: MQTT Reconnect
응답
19. 7. 9 오전 6:32 as a reply to Padmapriya G.

Hello Padmapriya,

can you share your code and what exactly you have tried to replicate my error?

I revisited my code several times step by step and i can't come to think where an error might be located. Therefore your working code might be of help.

 

Thank you,

Martin

0 (0 투표)
RE: MQTT Reconnect
응답
19. 7. 10 오전 8:59 as a reply to Martin Scheck.

Hello Martin,

I used SendDataOverMQTT application from XDK workbench v3.6.0 and done some modifications in

  1. AppController.c -> AppControllerValidateWLANConnectivity
  2. static Retcode_T AppControllerValidateWLANConnectivity(void)
    {
        Retcode_T retcode = RETCODE_OK;
        WlanNetworkConnect_IpStatus_T nwStatus;
    
        nwStatus = WlanNetworkConnect_GetIpStatus();
        if (WLANNWCT_IPSTATUS_CT_AQRD != nwStatus)
        {
    #if APP_MQTT_SECURE_ENABLE
            static bool isSntpDisabled = false;
            if (false == isSntpDisabled)
            {
                retcode = SNTP_Disable();
            }
            if (RETCODE_OK == retcode)
            {
                isSntpDisabled = true;
                retcode = WLAN_Reconnect();
            }
            if (RETCODE_OK == retcode)
            {
                retcode = SNTP_Enable();
            }
    #else
            retcode = WLAN_Reconnect();
    #endif /* APP_MQTT_SECURE_ENABLE */
        }
        return retcode;
    }
    
  3. AppController.c -> AppControllerFire function -> while loop
  4.    while (1)
        {
            /* Resetting / clearing the necessary buffers / variables for re-use */
            retcode = RETCODE_OK;
    
            /* Check whether the WLAN network connection is available */
            retcode = AppControllerValidateWLANConnectivity();
    		if (RETCODE_OK == retcode)
    		{
    	        /* Check for MQTT broker connection */
    	        retcode = MQTT_IsConnected();
    	        if (RETCODE_OK != retcode)
    	        {
    	        	printf("AppControllerFire : Re-connecting with MQTT broker... \n\r");
    	    		retcode = MQTT_ConnectToBroker(&MqttConnectInfo, MQTT_CONNECT_TIMEOUT_IN_MS);
    	    		if (RETCODE_OK == retcode)
    	    		{
    	    			retcode = MQTT_SubsribeToTopic(&MqttSubscribeInfo, MQTT_SUBSCRIBE_TIMEOUT_IN_MS);
    	    		}
    	        }
    		}
    		if (RETCODE_OK == retcode)
    		{
    			retcode = Sensor_GetData(&sensorValue);
    		}
    		if (RETCODE_OK == retcode)
    		{
    			int32_t length = snprintf((char *) publishBuffer, APP_MQTT_DATA_BUFFER_SIZE, publishDataFormat,
    					(long int) sensorValue.RH, (long int) sensorValue.Pressure,
    					(sensorValue.Temp /= 1000));
    
    			MqttPublishInfo.Payload = publishBuffer;
    			MqttPublishInfo.PayloadLength = length;
    
    			retcode = MQTT_PublishToTopic(&MqttPublishInfo, MQTT_PUBLISH_TIMEOUT_IN_MS);
    			if (RETCODE_OK != retcode)
    			{
    				printf("AppControllerFire : MQTT publish failed \n\r");
    			}
    		}
            if (RETCODE_OK != retcode)
            {
                Retcode_RaiseError(retcode);
            }
            vTaskDelay(APP_MQTT_DATA_PUBLISH_PERIODICITY);
        }
    Retcode_T MQTT_IsConnected(void)
    {
        Retcode_T retcode = RETCODE_OK;
        if (false == Mqtt_isConnected(&MqttSession))
        {
            retcode = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_MQTT_DISCONNECT);
        }
        return retcode;
    }

     

0 (0 투표)
RE: MQTT Reconnect
응답
19. 7. 15 오전 7:17 as a reply to Padmapriya G.

Hello Padmapriya,

Thank you for your response.

 

Using your code even when the session is connected it automatically tries to reconnect.

Also, why do you use a seperate "MQTT_IsConnected(void)" function, when all it does is calling the "bool Mqtt_isConnected(const MqttSession_T* session)"? Can't you just call it straight up and check the bool returnvalue if its connected or not?

Furthermore, when i check if the Mqtt Session is connected i get a false value, even though the last step was a succesful establishing of the Connection and acknowledging of the subscription.

The following is the console output i get with your code. It works once and then fails again.

INFO | XDK DEVICE 2: WLANPersonalWPA2Connect : Connected to WPA network successfully. 
 INFO | XDK DEVICE 2: MqttEventHandler : Event - 0
 INFO | XDK DEVICE 2: MQTT_SubsribeToTopic : Subscribing to topic: Test2, Qos: 1
 INFO | XDK DEVICE 2: MqttEventHandler : Event - 8
 INFO | XDK DEVICE 2: AppControllerFire : Re-connecting with MQTT broker... 
 INFO | XDK DEVICE 2: MqttEventHandler : Event - 0
 INFO | XDK DEVICE 2: MQTT_SubsribeToTopic : Subscribing to topic: Test2, Qos: 1
 INFO | XDK DEVICE 2: MqttEventHandler : Event - 8
 INFO | XDK DEVICE 2: MqttEventHandler : Event - 15
 INFO | XDK DEVICE 2: MqttEventHandler : Event - 14
 INFO | XDK DEVICE 2: AppMQTTSubscribeCB : #1, Incoming Message:
 INFO | XDK DEVICE 2: 	Topic: Test2
 INFO | XDK DEVICE 2: 	Payload: 
 INFO | XDK DEVICE 2: """
 INFO | XDK DEVICE 2: Environmental Data -
 INFO | XDK DEVICE 2: 	Humidity : 30
 INFO | XDK DEVICE 2: 	Pressure : 100126
 INFO | XDK DEVICE 2: 	Temperature : 31.751000ø
 INFO | XDK DEVICE 2: """
 INFO | XDK DEVICE 2: AppControllerFire : Re-connecting with MQTT broker... 
 INFO | XDK DEVICE 2: MqttEventHandler : Event - 2
 INFO | XDK DEVICE 2: MqttEventHandler : Event - 4
 INFO | XDK DEVICE 2: Error in XDK110 Application package.
 INFO | XDK DEVICE 2: Error in XDK110 Application package.
 INFO | XDK DEVICE 2: 	Package ID: 153
 INFO | XDK DEVICE 2: 	Package ID: 153
 INFO | XDK DEVICE 2: 	Module ID: 39
 INFO | XDK DEVICE 2: 	Module ID: 39
 INFO | XDK DEVICE 2: 	Severity code: 2
 INFO | XDK DEVICE 2: 	Severity code: 2
 INFO | XDK DEVICE 2: 	Error code: 122
 INFO | XDK DEVICE 2: 	Error code: 123
 INFO | XDK DEVICE 2: AppControllerFire : Re-connecting with MQTT broker... 
 INFO | XDK DEVICE 2: MQTT_ConnectToBroker : Failed to connect MQTT 
 INFO | XDK DEVICE 2: Error in XDK110 Application package.
 INFO | XDK DEVICE 2: 	Package ID: 153
 INFO | XDK DEVICE 2: 	Module ID: 39
 INFO | XDK DEVICE 2: 	Severity code: 2
 INFO | XDK DEVICE 2: 	Error code: 117

the only change i did to shorten the code is the following in AppController.c -> in the while loop

retcode = AppControllerValidateWLANConnectivity();

        if (RETCODE_OK == retcode)
        {
        /* Check for MQTT broker connection */
        	if (!Mqtt_isConnected(&MqttConnectInfo))
        	{
        		printf("AppControllerFire : Re-connecting with MQTT broker... \n\r");
        	    retcode = MQTT_ConnectToBroker(&MqttConnectInfo, MQTT_CONNECT_TIMEOUT_IN_MS);
        	    if (RETCODE_OK == retcode)
        	    {
        	    	printf("Connecting to Broker Succesful, subscribing to Topic\n\r");
        	    	retcode = MQTT_SubsribeToTopic(&MqttSubscribeInfo, MQTT_SUBSCRIBE_TIMEOUT_IN_MS);
        	    }
        	}
        }

 

I somehow get the feeling, that the Mqtt_isConnected function in the Mqtt.c is broken, due it having a:

"    //todo actually check status" which doesn't indicate that its working correctly.

 

Also what is different from your code to my initial code is that you just connect over again and not properly disconnect => reeinitialize and then reconnect. So what should be the right way to cleanly reconnect to be sure it works in any case?

0 (0 투표)
RE: MQTT Reconnect
응답
19. 7. 16 오전 6:16 as a reply to Martin Scheck.

I worked around the MQTT Reconnect by using the System restart/reboot function explained in this topic: 

https://xdk.bosch-connectivity.com/de/community/-/message_boards/message/399439

It's a working workaround, but hopefully the MQTT_isConnected function gets reviewed.

+1 (1 투표)