This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

MQTTSN Example: Client unable to reconnect to Broker after timeout

Hello,

I am currently using mqttsn publisher exams with keep allive time of 30 seconds, so according to MQTT standard if period of inactivity will be 45 second and the client is unable to recieve ping response or broker doesn't recieve ping request from client in fixed time it will break the connection.

I would like to know how could I reconnect client to the broker once the broker timesout the client connection. Currently I am checking the state of client using isConnected api but it indeed take 3-4 minutes to restablish a connection. 

I would like to re-establish a connection as soon as the mqtt-sn client get's time out. I can't wait for 2-3 minutes to connect to broker. Also currently I have to wait for the next publish to check whether my client is connected to broker or not.

For Example: if I take a python MQTT client with keep alive time of 60 second and turn off and turn on the mosquito broker , the python client immediately connects within few seconds. I want some solution like that for mqtt-sn client. 

Please provide some tried and tested code or help for the same.  

Parents
  • Hi Brian

    Have you changed the MQTT-SN sleepy publisher example?
    If you have changed the example, could you send the code you are running, so that I can try to reproduce your issue?

    I will also set up the Nordic Border Router Image to test with this.

    Regards,
    Sigurd Hellesvik

  • Hello Sigurd,

    I have used app timer instead of buttons for sending data.Else everything is same. I have provide my main.c file. I have tried  to establish an network with forever mesh connectivity. If for some reason mqttsn client gets timeout, it should send search request again and connect to gateway again. I tried to create a state machine using mqttsn events, so that every event is handled properly.

    - My keep alive time is set to 60.

    Here is my main.c file:

    /** @file
     *
     * @defgroup thread_mqttsn_sleepy_publisher_example_main main.c
     * @{
     * @ingroup thread_mqttsn_sleepy_publisher_example
     * @brief Thread MQTT-SN Sleepy Publisher Example Application main file.
     *
     * @details This example demonstrates an MQTT-SN sleepy publisher application that enables to toggle
     *          BSP_LED_2 on a board with related MQTT-SN sleepy subscriber application via MQTT-SN messages.
     *          As the MQTT-SN sleepy publisher has no subscriptions, it will not need to receive data except
     *          for ACKs for its own messages, so asynchronous receiving is not needed. It therefore serves
     *          as a Thread Sleepy End Device.
     */
    
    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include <stdio.h>
    #include "app_timer.h"
    #include "nrf_drv_clock.h"
    #include "bsp_thread.h"
    #include "nrf_assert.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "nrf_delay.h"
    #include "mqttsn_client.h"
    #include "thread_utils.h"
    
    
    #include <openthread/ip6.h>
    #include <openthread/thread.h>
    
    #define DEFAULT_CHILD_TIMEOUT    40                                         /**< Thread child timeout [s]. */
    #define DEFAULT_POLL_PERIOD      1000                                       /**< Thread Sleepy End Device polling period when MQTT-SN Asleep. [ms] */
    #define SHORT_POLL_PERIOD        10                                        /**< Thread Sleepy End Device polling period when MQTT-SN Awake. [ms] */
    #define SEARCH_GATEWAY_TIMEOUT   5                                          /**< MQTT-SN Gateway discovery procedure timeout in [s]. */                                   
    
    /* Macros */
    #define MQTTSN_PAYLOAD_SIZE 1000
    #define BATTERY_PERCENTAGE 99
    #define SNODE_UNIQUE_ID "wekmnjv"
    #define EPOCH_TIME 1234567 
    
    static mqttsn_client_t      m_client;                                       /**< An MQTT-SN client instance. */
    static mqttsn_remote_t      m_gateway_addr;                                 /**< A gateway address. */
    static uint8_t              m_gateway_id;                                   /**< A gateway ID. */
    static mqttsn_connect_opt_t m_connect_opt;                                  /**< Connect options for the MQTT-SN client. */
    static uint8_t              m_led_state        = 0;                         /**< Previously sent BSP_LED_2 command. */
    static uint16_t             m_msg_id           = 0;                         /**< Message ID thrown with MQTTSN_EVENT_TIMEOUT. */
    static char                 m_client_id[]      = "lsm";      /**< The MQTT-SN Client's ID. */
    static char                 m_topic_name[]     = "/snode/lsm"; /**< Name of the topic corresponding to subscriber's BSP_LED_2. */
    static mqttsn_topic_t       m_topic            =                            /**< Topic corresponding to subscriber's BSP_LED_2. */
    {
        .p_topic_name = (unsigned char *)m_topic_name,
        .topic_id     = 0,
    };
    
    volatile bool snode_ot_connection_status = false;
    volatile bool gateway_discovery_status = false;
    volatile bool device_connection_status = false;
    
    
    uint32_t MQTTSN_Client_Connect_Gateway(void);
    uint32_t MQTTSN_Client_Search_Gateway(void);
    
    
    //Timer Interval for MQTT-SN Tasks 
    #define SENSOR_UPDATE_INTERVAL APP_TIMER_TICKS(10000)
    
    //Handlers for MQTT-SN Tasks
    APP_TIMER_DEF(pub_data);  //Handler to publish data
    
    
    /**
      * @brief  Processes callback from Publish Data timer timeout.
                This function initiates the continous mqttsn publish 
                process at rate set by SENSOR_UPDATE_INTERVAL macro.
      * @param  p_context  default syntax
      * @retval None
    */
    void snode_publish_sensor_data_callback(void * p_context)
    {
        publish();
    }
    
    /**
     * @brief  Function to create Timers for MQTTSN Tasks
     * @param  None
     * @retval None
     */
    void MQTTSNTask_Timer_Init()
    {
        ret_code_t err_code;
    
        //Timer of sensor update
        err_code = app_timer_create(&pub_data,
                                    APP_TIMER_MODE_REPEATED,
                                    snode_publish_sensor_data_callback);
        APP_ERROR_CHECK(err_code);
    
    }
    
    
    
    /**
      * @brief  Function to start MQTT-SN client Publishing data
                timer in Repeated Mode . 
      * @param  None  
      * @retval err_code 0 = Successfull  Other =  Error
    */
    uint32_t SNode_Start_Publishing_Data_Timer(void)
    {
      uint32_t err_code = app_timer_start(pub_data,  SENSOR_UPDATE_INTERVAL, NULL);
      APP_ERROR_CHECK(err_code);
    
      return  err_code;
    }
    
    
    /**
      * @brief  Function to Stop MQTT-SN client Publishing timer. 
      * @param  None  
      * @retval err_code 0 = Successfull  Other =  Error
    */
    uint32_t SNode_Stop_Publishing_Data_Timer(void)
    {
        uint32_t err_code = app_timer_stop(pub_data);
        APP_ERROR_CHECK(err_code);
    
        return err_code;
    }
    
    
    
    /**@brief Function starting the internal LFCLK oscillator.
     *
     * @details This is needed by RTC1 which is used by the Application Timer
     *          (When SoftDevice is enabled the LFCLK is always running and this is not needed).
     */
    void lfclk_request(void)
    {
        ret_code_t err_code = nrf_drv_clock_init();
        APP_ERROR_CHECK(err_code);
        nrf_drv_clock_lfclk_request(NULL);
    }
     
    
    
    uint32_t MQTTSN_Client_Search_Gateway(void)
    {
    
      uint32_t err_code = NRF_SUCCESS;
    
      /* Search gateway only if client is disconnected*/
      if (mqttsn_client_state_get(&m_client) != MQTTSN_CLIENT_CONNECTED)
      {
        err_code = mqttsn_client_search_gateway(&m_client, SEARCH_GATEWAY_TIMEOUT);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("SEARCH GATEWAY message could not be sent. Error: 0x%x\r\n", err_code);
            printf("SEARCH GATEWAY message could not be sent. Error: 0x%x\r\n", err_code);
        }
        else
        {
          printf("Search Gateway message sent.\r\n");
        }
      
      }
    
      return err_code;
    }
    
    
    uint32_t MQTTSN_Client_Connect_Gateway(void)
    {
      uint32_t err_code = NRF_SUCCESS;
      
      /* Send Connection request only if Client is disconnected*/
      if (mqttsn_client_state_get(&m_client) != MQTTSN_CLIENT_CONNECTED)
      {
        err_code = mqttsn_client_connect(&m_client, &m_gateway_addr, m_gateway_id, &m_connect_opt);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("CONNECT message could not be sent. Error: 0x%x\r\n", err_code);
            printf("CONNECT message could not be sent. Error: 0x%x\r\n", err_code);
        }
      }
    
      return err_code;
    }
    
    /***************************************************************************************************
     * @section MQTT-SN
     **************************************************************************************************/
    
    /**@brief Turns the MQTT-SN network indication LED on.
     *
     * @details This LED is on when an MQTT-SN client is in connected or awake state.
     */
    static void light_on(void)
    {
        LEDS_ON(BSP_LED_3_MASK);
    }
    
    /**@brief Turns the MQTT-SN network indication LED off.
     *
     * @details This LED is on when an MQTT-SN client is in disconnected or asleep state.
     */
    static void light_off(void)
    {
        LEDS_OFF(BSP_LED_3_MASK);
    }
    
    /**@brief Puts MQTT-SN client in sleep mode.
     *
     * @details This function changes Thread Sleepy End Device polling period to default.
     */
    void sleep(void)
    {
        otError error;
        light_off();
    
        error = otLinkSetPollPeriod(thread_ot_instance_get(), DEFAULT_POLL_PERIOD);
        ASSERT(error == OT_ERROR_NONE);
    }
    
    /**@brief Puts MQTT-SN client in active mode.
     *
     * @details This function changes Thread Sleepy End Device polling period to short.
     */
    void wake_up(void)
    {
        otError error;
        light_on();
        printf("WakeUp: period to %d\r\n",SHORT_POLL_PERIOD);
    
        error = otLinkSetPollPeriod(thread_ot_instance_get(), SHORT_POLL_PERIOD);
        ASSERT(error == OT_ERROR_NONE);
    }
    
    /**@brief Initializes MQTT-SN client's connection options.
     */
    static void connect_opt_init(void)
    {
        m_connect_opt.alive_duration = MQTTSN_DEFAULT_ALIVE_DURATION,
        m_connect_opt.clean_session  = MQTTSN_DEFAULT_CLEAN_SESSION_FLAG,
        m_connect_opt.will_flag      = MQTTSN_DEFAULT_WILL_FLAG,
        m_connect_opt.client_id_len  = strlen(m_client_id),
    
        memcpy(m_connect_opt.p_client_id, (unsigned char *)m_client_id, m_connect_opt.client_id_len);
    }
    
    /**@brief Processes GWINFO message from a gateway.
     *
     * @details This function initializes MQTT-SN Client's connect options and launches the connect procedure.
     *
     * @param[in]    p_event  Pointer to MQTT-SN event.
     */
    static void gateway_info_callback(mqttsn_event_t * p_event)
    {
        m_gateway_addr  = *(p_event->event_data.connected.p_gateway_addr);
        m_gateway_id    = p_event->event_data.connected.gateway_id;
    }
    
    /**@brief Processes CONNACK message from a gateway.
     *
     * @details This function launches the topic registration procedure if necessary.
     */
    static void connected_callback(void)
    {
        light_on();
    
        uint32_t err_code = mqttsn_client_topic_register(&m_client,
                                                         m_topic.p_topic_name,
                                                         strlen(m_topic_name),
                                                         &m_msg_id);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("REGISTER message could not be sent. Error code: 0x%x\r\n", err_code);
            printf("REGISTER message could not be sent. Error code: 0x%x\r\n", err_code);
        }
    }
    
    /**@brief Processes DISCONNECT message from a gateway. */
    static void disconnected_callback(void)
    {
        light_off();
        sleep();
    }
    
    /**@brief Processes REGACK message from a gateway.
     *
     * @details This function puts the client in sleep mode.
     *
     * @param[in] p_event Pointer to MQTT-SN event.
     */
    static void regack_callback(mqttsn_event_t * p_event)
    {
        m_topic.topic_id = p_event->event_data.registered.packet.topic.topic_id;
        NRF_LOG_INFO("MQTT-SN event: Topic has been registered with ID: %d.\r\n",
                     p_event->event_data.registered.packet.topic.topic_id);
    
        printf("MQTT-SN event: Topic has been registered with ID: %d.\r\n",
                     p_event->event_data.registered.packet.topic.topic_id);
    
        sleep();
    }
    
    /**@brief Processes PUBACK message from a gateway.
     *
     * @details This function puts the client in sleep mode.
     */
    static void puback_callback(void)
    {
        sleep();
    }
    
    /**@brief Processes DISCONNECT message being a response to sleep request.
     *
     * @details This function puts the client in sleep mode.
     */
    static void sleep_callback(void)
    {
        sleep();
    }
    
    /**@brief Processes callback from keep-alive timer timeout.
     *
     * @details This function puts the client in active mode.
     */
    static void wakeup_callback(void)
    {
        wake_up();
    }
    
    /**@brief Processes retransmission limit reached event. */
    static void timeout_callback(mqttsn_event_t * p_event)
    {
        NRF_LOG_INFO("MQTT-SN event: Timed-out message: %d. Message ID: %d.\r\n",
                      p_event->event_data.error.msg_type,
                      p_event->event_data.error.msg_id);
    
        printf("MQTT-SN event: Timed-out message: %d. Message ID: %d.\r\n",
                      p_event->event_data.error.msg_type,
                      p_event->event_data.error.msg_id);
    }
    
    /**@brief Processes results of gateway discovery procedure. */
    static void searchgw_timeout_callback(mqttsn_event_t * p_event)
    {
        NRF_LOG_INFO("MQTT-SN event: Gateway discovery result: 0x%x.\r\n", p_event->event_data.discovery);
        printf("MQTT-SN event: Gateway discovery result: 0x%x.\r\n", p_event->event_data.discovery);
        sleep();
    }
    
    /**@brief Function for handling MQTT-SN events. */
    void mqttsn_evt_handler(mqttsn_client_t * p_client, mqttsn_event_t * p_event)
    {
        switch (p_event->event_id)
        {
            case MQTTSN_EVENT_GATEWAY_FOUND:
                gateway_discovery_status = true;
                NRF_LOG_INFO("MQTT-SN event: Client has found an active gateway.\r\n");
                printf("MQTT-SN event: Client has found an active gateway.\r\n");
                gateway_info_callback(p_event);
                wake_up();
                if (mqttsn_client_state_get(&m_client) != MQTTSN_CLIENT_CONNECTED)
                {
                  MQTTSN_Client_Connect_Gateway();
                }
                  
                break;
    
            case MQTTSN_EVENT_CONNECTED:
                device_connection_status = true;
                NRF_LOG_INFO("MQTT-SN event: Client connected.\r\n");
                printf("MQTT-SN event: Client connected.\r\n");
                connected_callback();
                SNode_Start_Publishing_Data_Timer();
                break;
    
            case MQTTSN_EVENT_DISCONNECTED:
                NRF_LOG_INFO("MQTT-SN event: Client disconnected.\r\n");
                printf("MQTT-SN event: Client disconnected.\r\n");
                disconnected_callback();
                break;
    
            case MQTTSN_EVENT_REGISTERED:
                NRF_LOG_INFO("MQTT-SN event: Client registered topic.\r\n");
                printf("MQTT-SN event: Client registered topic.\r\n");            
                regack_callback(p_event);
                break;
    
            case MQTTSN_EVENT_PUBLISHED:
                NRF_LOG_INFO("MQTT-SN event: Client has successfully published content.\r\n");
                printf("MQTT-SN event: Client has successfully published content.\r\n");            
                puback_callback();
                break;
    
            case MQTTSN_EVENT_SLEEP_PERMIT:
                NRF_LOG_INFO("MQTT-SN event: Client permitted to sleep.\r\n");
                printf("MQTT-SN event: Client permitted to sleep.\r\n");
                sleep_callback();
                break;
    
            case MQTTSN_EVENT_SLEEP_STOP:
                NRF_LOG_INFO("MQTT-SN event: Client wakes up.\r\n");
                printf("MQTT-SN event: Client wakes up.\r\n");
                wakeup_callback();
                break;
    
            case MQTTSN_EVENT_TIMEOUT:
                NRF_LOG_INFO("MQTT-SN event: Retransmission retries limit has been reached.\r\n");
                printf("MQTT-SN event: Retransmission retries limit has been reached.\r\n");
                timeout_callback(p_event);
    
                if(gateway_discovery_status == false && device_connection_status == false)
                {
                  MQTTSN_Client_Search_Gateway();
                }
                else if(gateway_discovery_status == true && mqttsn_client_state_get(&m_client) != MQTTSN_CLIENT_CONNECTED)
                {
                  MQTTSN_Client_Connect_Gateway();
                }
    
    
                break;
    
            case MQTTSN_EVENT_SEARCHGW_TIMEOUT:
                NRF_LOG_INFO("MQTT-SN event: Gateway discovery procedure has finished.\r\n");
                printf("MQTT-SN event: Gateway discovery procedure has finished.\r\n");
                searchgw_timeout_callback(p_event);
                if(gateway_discovery_status == false)
                {
                  MQTTSN_Client_Search_Gateway();
                }
                break;
    
            default:
                break;
        }
    }
    
    /***************************************************************************************************
     * @section State
     **************************************************************************************************/
    
    static void state_changed_callback(uint32_t flags, void * p_context)
    {
        NRF_LOG_INFO("State changed! Flags: 0x%08x Current role: %d\r\n",
                     flags, otThreadGetDeviceRole(p_context));
    }
    
    /***************************************************************************************************
     * @section Buttons
     **************************************************************************************************/
    
    static void led_state_pub(uint8_t led_state)
    {
        uint32_t err_code = mqttsn_client_publish(&m_client, m_topic.topic_id, &led_state, 1, &m_msg_id);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("PUBLISH message could not be sent. Error code: 0x%x\r\n", err_code)
        }
    }
    
    
    void publish(void)
    {
        uint8_t data_len=0;
        uint16_t total_len = 0;
        uint32_t err_code=0;
        uint8_t frame_cnt =0;
        int8_t rssi_value;
    
       /* Publish data only if MQTTSN Client is connected to Gateway */   
       if (mqttsn_client_state_get(&m_client) == MQTTSN_CLIENT_CONNECTED)
       {
         /* Read RSSI value */ 
         otThreadGetParentLastRssi(thread_ot_instance_get(),&rssi_value);
          
          char *txbuff = "Hello";
    
                 /* Read Sensor data */
            do
            {
          
              uint32_t err_code = mqttsn_client_publish(&m_client, m_topic.topic_id, txbuff, 5, &m_msg_id);
              if (err_code != NRF_SUCCESS)
              {
                  NRF_LOG_ERROR("PUBLISH message could not be sent. Error code: 0x%x\r\n", err_code)
              }
              nrf_delay_ms(100);
    
              frame_cnt+=1;
    
            }
            while(frame_cnt%1);
            frame_cnt = 0;
    
       }
       else
       {
          printf("Discnnected\r\n");
          gateway_discovery_status = false;
          device_connection_status = false;
    
          //Stop Publsihing data
          SNode_Stop_Publishing_Data_Timer();
          nrf_delay_ms(500);
    
          MQTTSN_Client_Search_Gateway();
       }
    
    
    }
    
    
    
    static void bsp_event_handler(bsp_event_t event)
    {
        if (otThreadGetDeviceRole(thread_ot_instance_get()) < OT_DEVICE_ROLE_CHILD )
        {
            (void)event;
            return;
        }
    
        switch (event)
        {
            case BSP_EVENT_KEY_1:
            {
                wake_up();
    
                uint32_t err_code = mqttsn_client_search_gateway(&m_client, SEARCH_GATEWAY_TIMEOUT);
                if (err_code != NRF_SUCCESS)
                {
                    NRF_LOG_ERROR("SEARCH GATEWAY message could not be sent. Error: 0x%x\r\n", err_code);
                }
                break;
            }
    
            case BSP_EVENT_KEY_2:
            {
                wake_up();
    
                uint32_t err_code;
    
                if (mqttsn_client_state_get(&m_client) == MQTTSN_CLIENT_CONNECTED)
                {
                    err_code = mqttsn_client_disconnect(&m_client);
                    if (err_code != NRF_SUCCESS)
                    {
                        NRF_LOG_ERROR("DISCONNECT message could not be sent. Error: 0x%x\r\n", err_code);
                    }
                }
                else
                {
                    err_code = mqttsn_client_connect(&m_client, &m_gateway_addr, m_gateway_id, &m_connect_opt);
                    if (err_code != NRF_SUCCESS)
                    {
                        NRF_LOG_ERROR("CONNECT message could not be sent. Error: 0x%x\r\n", err_code);
                    }
                }
                break;
            }
    
            case BSP_EVENT_KEY_3:
            {
                wake_up();
                publish();
                break;
            }
    
            default:
            {
                break;
            }
        }
    }
    
    /***************************************************************************************************
     * @section Initialization
     **************************************************************************************************/
    
    /**@brief Function for initializing the Application Timer Module.
     */
    static void timer_init(void)
    {
        uint32_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing the LEDs.
     */
    static void leds_init(void)
    {
        LEDS_CONFIGURE(LEDS_MASK);
        LEDS_OFF(LEDS_MASK);
    }
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    /**@brief Function for initializing the Thread Board Support Package.
     */
    static void thread_bsp_init(void)
    {
        uint32_t err_code;
        err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_thread_init(thread_ot_instance_get());
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing the Thread Stack.
     */
    static void thread_instance_init(void)
    {
        thread_configuration_t thread_configuration =
        {
            .radio_mode            = THREAD_RADIO_MODE_RX_OFF_WHEN_IDLE,
            .autocommissioning     = true,
            .poll_period           = DEFAULT_POLL_PERIOD,
            .default_child_timeout = DEFAULT_CHILD_TIMEOUT,
        };
    
        thread_init(&thread_configuration);
        thread_state_changed_callback_set(state_changed_callback);
    }
    
    /**@brief Function for initializing the MQTTSN client.
     */
    static void mqttsn_init(void)
    {
        uint32_t err_code = mqttsn_client_init(&m_client,
                                               MQTTSN_DEFAULT_CLIENT_PORT,
                                               mqttsn_evt_handler,
                                               thread_ot_instance_get());
        APP_ERROR_CHECK(err_code);
    
        connect_opt_init();
    }
    
    
    
    
    
    
    /***************************************************************************************************
     * @section Main
     **************************************************************************************************/
    
    int main(int argc, char *argv[])
    {
        uint32_t err_code;
    
        log_init();
        timer_init();
        leds_init();
    
        lfclk_request();
        app_timer_init();
        MQTTSNTask_Timer_Init();
    
        thread_instance_init();
        thread_bsp_init();
        mqttsn_init();
    
        //InitTargetPlatform();
        while (true)
        {
          /* Used to send search gateway packet after device gets attached to a thread network for first time 
           OR device gets detached and than get attached to network.  */
          if(otThreadGetDeviceRole(thread_ot_instance_get()) >= OT_DEVICE_ROLE_CHILD && snode_ot_connection_status == false)
          {
            wake_up();
            do
            {
              err_code = MQTTSN_Client_Search_Gateway();
              nrf_delay_ms(500);
            } 
            while(err_code != NRF_SUCCESS);  
            snode_ot_connection_status = true;
          }
    
          thread_process();
    
          if (NRF_LOG_PROCESS() == false)
          {
              thread_sleep();
          }
        }
    }
    
    /**
     *@}
     **/
    

    Also do tell me if there is any problem in my code ? As i said i want to establish a state machine type code, so that decisions are made based on events automatically. 

    Thanks.

Reply
  • Hello Sigurd,

    I have used app timer instead of buttons for sending data.Else everything is same. I have provide my main.c file. I have tried  to establish an network with forever mesh connectivity. If for some reason mqttsn client gets timeout, it should send search request again and connect to gateway again. I tried to create a state machine using mqttsn events, so that every event is handled properly.

    - My keep alive time is set to 60.

    Here is my main.c file:

    /** @file
     *
     * @defgroup thread_mqttsn_sleepy_publisher_example_main main.c
     * @{
     * @ingroup thread_mqttsn_sleepy_publisher_example
     * @brief Thread MQTT-SN Sleepy Publisher Example Application main file.
     *
     * @details This example demonstrates an MQTT-SN sleepy publisher application that enables to toggle
     *          BSP_LED_2 on a board with related MQTT-SN sleepy subscriber application via MQTT-SN messages.
     *          As the MQTT-SN sleepy publisher has no subscriptions, it will not need to receive data except
     *          for ACKs for its own messages, so asynchronous receiving is not needed. It therefore serves
     *          as a Thread Sleepy End Device.
     */
    
    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include <stdio.h>
    #include "app_timer.h"
    #include "nrf_drv_clock.h"
    #include "bsp_thread.h"
    #include "nrf_assert.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "nrf_delay.h"
    #include "mqttsn_client.h"
    #include "thread_utils.h"
    
    
    #include <openthread/ip6.h>
    #include <openthread/thread.h>
    
    #define DEFAULT_CHILD_TIMEOUT    40                                         /**< Thread child timeout [s]. */
    #define DEFAULT_POLL_PERIOD      1000                                       /**< Thread Sleepy End Device polling period when MQTT-SN Asleep. [ms] */
    #define SHORT_POLL_PERIOD        10                                        /**< Thread Sleepy End Device polling period when MQTT-SN Awake. [ms] */
    #define SEARCH_GATEWAY_TIMEOUT   5                                          /**< MQTT-SN Gateway discovery procedure timeout in [s]. */                                   
    
    /* Macros */
    #define MQTTSN_PAYLOAD_SIZE 1000
    #define BATTERY_PERCENTAGE 99
    #define SNODE_UNIQUE_ID "wekmnjv"
    #define EPOCH_TIME 1234567 
    
    static mqttsn_client_t      m_client;                                       /**< An MQTT-SN client instance. */
    static mqttsn_remote_t      m_gateway_addr;                                 /**< A gateway address. */
    static uint8_t              m_gateway_id;                                   /**< A gateway ID. */
    static mqttsn_connect_opt_t m_connect_opt;                                  /**< Connect options for the MQTT-SN client. */
    static uint8_t              m_led_state        = 0;                         /**< Previously sent BSP_LED_2 command. */
    static uint16_t             m_msg_id           = 0;                         /**< Message ID thrown with MQTTSN_EVENT_TIMEOUT. */
    static char                 m_client_id[]      = "lsm";      /**< The MQTT-SN Client's ID. */
    static char                 m_topic_name[]     = "/snode/lsm"; /**< Name of the topic corresponding to subscriber's BSP_LED_2. */
    static mqttsn_topic_t       m_topic            =                            /**< Topic corresponding to subscriber's BSP_LED_2. */
    {
        .p_topic_name = (unsigned char *)m_topic_name,
        .topic_id     = 0,
    };
    
    volatile bool snode_ot_connection_status = false;
    volatile bool gateway_discovery_status = false;
    volatile bool device_connection_status = false;
    
    
    uint32_t MQTTSN_Client_Connect_Gateway(void);
    uint32_t MQTTSN_Client_Search_Gateway(void);
    
    
    //Timer Interval for MQTT-SN Tasks 
    #define SENSOR_UPDATE_INTERVAL APP_TIMER_TICKS(10000)
    
    //Handlers for MQTT-SN Tasks
    APP_TIMER_DEF(pub_data);  //Handler to publish data
    
    
    /**
      * @brief  Processes callback from Publish Data timer timeout.
                This function initiates the continous mqttsn publish 
                process at rate set by SENSOR_UPDATE_INTERVAL macro.
      * @param  p_context  default syntax
      * @retval None
    */
    void snode_publish_sensor_data_callback(void * p_context)
    {
        publish();
    }
    
    /**
     * @brief  Function to create Timers for MQTTSN Tasks
     * @param  None
     * @retval None
     */
    void MQTTSNTask_Timer_Init()
    {
        ret_code_t err_code;
    
        //Timer of sensor update
        err_code = app_timer_create(&pub_data,
                                    APP_TIMER_MODE_REPEATED,
                                    snode_publish_sensor_data_callback);
        APP_ERROR_CHECK(err_code);
    
    }
    
    
    
    /**
      * @brief  Function to start MQTT-SN client Publishing data
                timer in Repeated Mode . 
      * @param  None  
      * @retval err_code 0 = Successfull  Other =  Error
    */
    uint32_t SNode_Start_Publishing_Data_Timer(void)
    {
      uint32_t err_code = app_timer_start(pub_data,  SENSOR_UPDATE_INTERVAL, NULL);
      APP_ERROR_CHECK(err_code);
    
      return  err_code;
    }
    
    
    /**
      * @brief  Function to Stop MQTT-SN client Publishing timer. 
      * @param  None  
      * @retval err_code 0 = Successfull  Other =  Error
    */
    uint32_t SNode_Stop_Publishing_Data_Timer(void)
    {
        uint32_t err_code = app_timer_stop(pub_data);
        APP_ERROR_CHECK(err_code);
    
        return err_code;
    }
    
    
    
    /**@brief Function starting the internal LFCLK oscillator.
     *
     * @details This is needed by RTC1 which is used by the Application Timer
     *          (When SoftDevice is enabled the LFCLK is always running and this is not needed).
     */
    void lfclk_request(void)
    {
        ret_code_t err_code = nrf_drv_clock_init();
        APP_ERROR_CHECK(err_code);
        nrf_drv_clock_lfclk_request(NULL);
    }
     
    
    
    uint32_t MQTTSN_Client_Search_Gateway(void)
    {
    
      uint32_t err_code = NRF_SUCCESS;
    
      /* Search gateway only if client is disconnected*/
      if (mqttsn_client_state_get(&m_client) != MQTTSN_CLIENT_CONNECTED)
      {
        err_code = mqttsn_client_search_gateway(&m_client, SEARCH_GATEWAY_TIMEOUT);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("SEARCH GATEWAY message could not be sent. Error: 0x%x\r\n", err_code);
            printf("SEARCH GATEWAY message could not be sent. Error: 0x%x\r\n", err_code);
        }
        else
        {
          printf("Search Gateway message sent.\r\n");
        }
      
      }
    
      return err_code;
    }
    
    
    uint32_t MQTTSN_Client_Connect_Gateway(void)
    {
      uint32_t err_code = NRF_SUCCESS;
      
      /* Send Connection request only if Client is disconnected*/
      if (mqttsn_client_state_get(&m_client) != MQTTSN_CLIENT_CONNECTED)
      {
        err_code = mqttsn_client_connect(&m_client, &m_gateway_addr, m_gateway_id, &m_connect_opt);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("CONNECT message could not be sent. Error: 0x%x\r\n", err_code);
            printf("CONNECT message could not be sent. Error: 0x%x\r\n", err_code);
        }
      }
    
      return err_code;
    }
    
    /***************************************************************************************************
     * @section MQTT-SN
     **************************************************************************************************/
    
    /**@brief Turns the MQTT-SN network indication LED on.
     *
     * @details This LED is on when an MQTT-SN client is in connected or awake state.
     */
    static void light_on(void)
    {
        LEDS_ON(BSP_LED_3_MASK);
    }
    
    /**@brief Turns the MQTT-SN network indication LED off.
     *
     * @details This LED is on when an MQTT-SN client is in disconnected or asleep state.
     */
    static void light_off(void)
    {
        LEDS_OFF(BSP_LED_3_MASK);
    }
    
    /**@brief Puts MQTT-SN client in sleep mode.
     *
     * @details This function changes Thread Sleepy End Device polling period to default.
     */
    void sleep(void)
    {
        otError error;
        light_off();
    
        error = otLinkSetPollPeriod(thread_ot_instance_get(), DEFAULT_POLL_PERIOD);
        ASSERT(error == OT_ERROR_NONE);
    }
    
    /**@brief Puts MQTT-SN client in active mode.
     *
     * @details This function changes Thread Sleepy End Device polling period to short.
     */
    void wake_up(void)
    {
        otError error;
        light_on();
        printf("WakeUp: period to %d\r\n",SHORT_POLL_PERIOD);
    
        error = otLinkSetPollPeriod(thread_ot_instance_get(), SHORT_POLL_PERIOD);
        ASSERT(error == OT_ERROR_NONE);
    }
    
    /**@brief Initializes MQTT-SN client's connection options.
     */
    static void connect_opt_init(void)
    {
        m_connect_opt.alive_duration = MQTTSN_DEFAULT_ALIVE_DURATION,
        m_connect_opt.clean_session  = MQTTSN_DEFAULT_CLEAN_SESSION_FLAG,
        m_connect_opt.will_flag      = MQTTSN_DEFAULT_WILL_FLAG,
        m_connect_opt.client_id_len  = strlen(m_client_id),
    
        memcpy(m_connect_opt.p_client_id, (unsigned char *)m_client_id, m_connect_opt.client_id_len);
    }
    
    /**@brief Processes GWINFO message from a gateway.
     *
     * @details This function initializes MQTT-SN Client's connect options and launches the connect procedure.
     *
     * @param[in]    p_event  Pointer to MQTT-SN event.
     */
    static void gateway_info_callback(mqttsn_event_t * p_event)
    {
        m_gateway_addr  = *(p_event->event_data.connected.p_gateway_addr);
        m_gateway_id    = p_event->event_data.connected.gateway_id;
    }
    
    /**@brief Processes CONNACK message from a gateway.
     *
     * @details This function launches the topic registration procedure if necessary.
     */
    static void connected_callback(void)
    {
        light_on();
    
        uint32_t err_code = mqttsn_client_topic_register(&m_client,
                                                         m_topic.p_topic_name,
                                                         strlen(m_topic_name),
                                                         &m_msg_id);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("REGISTER message could not be sent. Error code: 0x%x\r\n", err_code);
            printf("REGISTER message could not be sent. Error code: 0x%x\r\n", err_code);
        }
    }
    
    /**@brief Processes DISCONNECT message from a gateway. */
    static void disconnected_callback(void)
    {
        light_off();
        sleep();
    }
    
    /**@brief Processes REGACK message from a gateway.
     *
     * @details This function puts the client in sleep mode.
     *
     * @param[in] p_event Pointer to MQTT-SN event.
     */
    static void regack_callback(mqttsn_event_t * p_event)
    {
        m_topic.topic_id = p_event->event_data.registered.packet.topic.topic_id;
        NRF_LOG_INFO("MQTT-SN event: Topic has been registered with ID: %d.\r\n",
                     p_event->event_data.registered.packet.topic.topic_id);
    
        printf("MQTT-SN event: Topic has been registered with ID: %d.\r\n",
                     p_event->event_data.registered.packet.topic.topic_id);
    
        sleep();
    }
    
    /**@brief Processes PUBACK message from a gateway.
     *
     * @details This function puts the client in sleep mode.
     */
    static void puback_callback(void)
    {
        sleep();
    }
    
    /**@brief Processes DISCONNECT message being a response to sleep request.
     *
     * @details This function puts the client in sleep mode.
     */
    static void sleep_callback(void)
    {
        sleep();
    }
    
    /**@brief Processes callback from keep-alive timer timeout.
     *
     * @details This function puts the client in active mode.
     */
    static void wakeup_callback(void)
    {
        wake_up();
    }
    
    /**@brief Processes retransmission limit reached event. */
    static void timeout_callback(mqttsn_event_t * p_event)
    {
        NRF_LOG_INFO("MQTT-SN event: Timed-out message: %d. Message ID: %d.\r\n",
                      p_event->event_data.error.msg_type,
                      p_event->event_data.error.msg_id);
    
        printf("MQTT-SN event: Timed-out message: %d. Message ID: %d.\r\n",
                      p_event->event_data.error.msg_type,
                      p_event->event_data.error.msg_id);
    }
    
    /**@brief Processes results of gateway discovery procedure. */
    static void searchgw_timeout_callback(mqttsn_event_t * p_event)
    {
        NRF_LOG_INFO("MQTT-SN event: Gateway discovery result: 0x%x.\r\n", p_event->event_data.discovery);
        printf("MQTT-SN event: Gateway discovery result: 0x%x.\r\n", p_event->event_data.discovery);
        sleep();
    }
    
    /**@brief Function for handling MQTT-SN events. */
    void mqttsn_evt_handler(mqttsn_client_t * p_client, mqttsn_event_t * p_event)
    {
        switch (p_event->event_id)
        {
            case MQTTSN_EVENT_GATEWAY_FOUND:
                gateway_discovery_status = true;
                NRF_LOG_INFO("MQTT-SN event: Client has found an active gateway.\r\n");
                printf("MQTT-SN event: Client has found an active gateway.\r\n");
                gateway_info_callback(p_event);
                wake_up();
                if (mqttsn_client_state_get(&m_client) != MQTTSN_CLIENT_CONNECTED)
                {
                  MQTTSN_Client_Connect_Gateway();
                }
                  
                break;
    
            case MQTTSN_EVENT_CONNECTED:
                device_connection_status = true;
                NRF_LOG_INFO("MQTT-SN event: Client connected.\r\n");
                printf("MQTT-SN event: Client connected.\r\n");
                connected_callback();
                SNode_Start_Publishing_Data_Timer();
                break;
    
            case MQTTSN_EVENT_DISCONNECTED:
                NRF_LOG_INFO("MQTT-SN event: Client disconnected.\r\n");
                printf("MQTT-SN event: Client disconnected.\r\n");
                disconnected_callback();
                break;
    
            case MQTTSN_EVENT_REGISTERED:
                NRF_LOG_INFO("MQTT-SN event: Client registered topic.\r\n");
                printf("MQTT-SN event: Client registered topic.\r\n");            
                regack_callback(p_event);
                break;
    
            case MQTTSN_EVENT_PUBLISHED:
                NRF_LOG_INFO("MQTT-SN event: Client has successfully published content.\r\n");
                printf("MQTT-SN event: Client has successfully published content.\r\n");            
                puback_callback();
                break;
    
            case MQTTSN_EVENT_SLEEP_PERMIT:
                NRF_LOG_INFO("MQTT-SN event: Client permitted to sleep.\r\n");
                printf("MQTT-SN event: Client permitted to sleep.\r\n");
                sleep_callback();
                break;
    
            case MQTTSN_EVENT_SLEEP_STOP:
                NRF_LOG_INFO("MQTT-SN event: Client wakes up.\r\n");
                printf("MQTT-SN event: Client wakes up.\r\n");
                wakeup_callback();
                break;
    
            case MQTTSN_EVENT_TIMEOUT:
                NRF_LOG_INFO("MQTT-SN event: Retransmission retries limit has been reached.\r\n");
                printf("MQTT-SN event: Retransmission retries limit has been reached.\r\n");
                timeout_callback(p_event);
    
                if(gateway_discovery_status == false && device_connection_status == false)
                {
                  MQTTSN_Client_Search_Gateway();
                }
                else if(gateway_discovery_status == true && mqttsn_client_state_get(&m_client) != MQTTSN_CLIENT_CONNECTED)
                {
                  MQTTSN_Client_Connect_Gateway();
                }
    
    
                break;
    
            case MQTTSN_EVENT_SEARCHGW_TIMEOUT:
                NRF_LOG_INFO("MQTT-SN event: Gateway discovery procedure has finished.\r\n");
                printf("MQTT-SN event: Gateway discovery procedure has finished.\r\n");
                searchgw_timeout_callback(p_event);
                if(gateway_discovery_status == false)
                {
                  MQTTSN_Client_Search_Gateway();
                }
                break;
    
            default:
                break;
        }
    }
    
    /***************************************************************************************************
     * @section State
     **************************************************************************************************/
    
    static void state_changed_callback(uint32_t flags, void * p_context)
    {
        NRF_LOG_INFO("State changed! Flags: 0x%08x Current role: %d\r\n",
                     flags, otThreadGetDeviceRole(p_context));
    }
    
    /***************************************************************************************************
     * @section Buttons
     **************************************************************************************************/
    
    static void led_state_pub(uint8_t led_state)
    {
        uint32_t err_code = mqttsn_client_publish(&m_client, m_topic.topic_id, &led_state, 1, &m_msg_id);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("PUBLISH message could not be sent. Error code: 0x%x\r\n", err_code)
        }
    }
    
    
    void publish(void)
    {
        uint8_t data_len=0;
        uint16_t total_len = 0;
        uint32_t err_code=0;
        uint8_t frame_cnt =0;
        int8_t rssi_value;
    
       /* Publish data only if MQTTSN Client is connected to Gateway */   
       if (mqttsn_client_state_get(&m_client) == MQTTSN_CLIENT_CONNECTED)
       {
         /* Read RSSI value */ 
         otThreadGetParentLastRssi(thread_ot_instance_get(),&rssi_value);
          
          char *txbuff = "Hello";
    
                 /* Read Sensor data */
            do
            {
          
              uint32_t err_code = mqttsn_client_publish(&m_client, m_topic.topic_id, txbuff, 5, &m_msg_id);
              if (err_code != NRF_SUCCESS)
              {
                  NRF_LOG_ERROR("PUBLISH message could not be sent. Error code: 0x%x\r\n", err_code)
              }
              nrf_delay_ms(100);
    
              frame_cnt+=1;
    
            }
            while(frame_cnt%1);
            frame_cnt = 0;
    
       }
       else
       {
          printf("Discnnected\r\n");
          gateway_discovery_status = false;
          device_connection_status = false;
    
          //Stop Publsihing data
          SNode_Stop_Publishing_Data_Timer();
          nrf_delay_ms(500);
    
          MQTTSN_Client_Search_Gateway();
       }
    
    
    }
    
    
    
    static void bsp_event_handler(bsp_event_t event)
    {
        if (otThreadGetDeviceRole(thread_ot_instance_get()) < OT_DEVICE_ROLE_CHILD )
        {
            (void)event;
            return;
        }
    
        switch (event)
        {
            case BSP_EVENT_KEY_1:
            {
                wake_up();
    
                uint32_t err_code = mqttsn_client_search_gateway(&m_client, SEARCH_GATEWAY_TIMEOUT);
                if (err_code != NRF_SUCCESS)
                {
                    NRF_LOG_ERROR("SEARCH GATEWAY message could not be sent. Error: 0x%x\r\n", err_code);
                }
                break;
            }
    
            case BSP_EVENT_KEY_2:
            {
                wake_up();
    
                uint32_t err_code;
    
                if (mqttsn_client_state_get(&m_client) == MQTTSN_CLIENT_CONNECTED)
                {
                    err_code = mqttsn_client_disconnect(&m_client);
                    if (err_code != NRF_SUCCESS)
                    {
                        NRF_LOG_ERROR("DISCONNECT message could not be sent. Error: 0x%x\r\n", err_code);
                    }
                }
                else
                {
                    err_code = mqttsn_client_connect(&m_client, &m_gateway_addr, m_gateway_id, &m_connect_opt);
                    if (err_code != NRF_SUCCESS)
                    {
                        NRF_LOG_ERROR("CONNECT message could not be sent. Error: 0x%x\r\n", err_code);
                    }
                }
                break;
            }
    
            case BSP_EVENT_KEY_3:
            {
                wake_up();
                publish();
                break;
            }
    
            default:
            {
                break;
            }
        }
    }
    
    /***************************************************************************************************
     * @section Initialization
     **************************************************************************************************/
    
    /**@brief Function for initializing the Application Timer Module.
     */
    static void timer_init(void)
    {
        uint32_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing the LEDs.
     */
    static void leds_init(void)
    {
        LEDS_CONFIGURE(LEDS_MASK);
        LEDS_OFF(LEDS_MASK);
    }
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    /**@brief Function for initializing the Thread Board Support Package.
     */
    static void thread_bsp_init(void)
    {
        uint32_t err_code;
        err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_thread_init(thread_ot_instance_get());
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing the Thread Stack.
     */
    static void thread_instance_init(void)
    {
        thread_configuration_t thread_configuration =
        {
            .radio_mode            = THREAD_RADIO_MODE_RX_OFF_WHEN_IDLE,
            .autocommissioning     = true,
            .poll_period           = DEFAULT_POLL_PERIOD,
            .default_child_timeout = DEFAULT_CHILD_TIMEOUT,
        };
    
        thread_init(&thread_configuration);
        thread_state_changed_callback_set(state_changed_callback);
    }
    
    /**@brief Function for initializing the MQTTSN client.
     */
    static void mqttsn_init(void)
    {
        uint32_t err_code = mqttsn_client_init(&m_client,
                                               MQTTSN_DEFAULT_CLIENT_PORT,
                                               mqttsn_evt_handler,
                                               thread_ot_instance_get());
        APP_ERROR_CHECK(err_code);
    
        connect_opt_init();
    }
    
    
    
    
    
    
    /***************************************************************************************************
     * @section Main
     **************************************************************************************************/
    
    int main(int argc, char *argv[])
    {
        uint32_t err_code;
    
        log_init();
        timer_init();
        leds_init();
    
        lfclk_request();
        app_timer_init();
        MQTTSNTask_Timer_Init();
    
        thread_instance_init();
        thread_bsp_init();
        mqttsn_init();
    
        //InitTargetPlatform();
        while (true)
        {
          /* Used to send search gateway packet after device gets attached to a thread network for first time 
           OR device gets detached and than get attached to network.  */
          if(otThreadGetDeviceRole(thread_ot_instance_get()) >= OT_DEVICE_ROLE_CHILD && snode_ot_connection_status == false)
          {
            wake_up();
            do
            {
              err_code = MQTTSN_Client_Search_Gateway();
              nrf_delay_ms(500);
            } 
            while(err_code != NRF_SUCCESS);  
            snode_ot_connection_status = true;
          }
    
          thread_process();
    
          if (NRF_LOG_PROCESS() == false)
          {
              thread_sleep();
          }
        }
    }
    
    /**
     *@}
     **/
    

    Also do tell me if there is any problem in my code ? As i said i want to establish a state machine type code, so that decisions are made based on events automatically. 

    Thanks.

Children
No Data
Related