Page 1 of 1

MQTT memory leaks while reconnecting Wi-Fi

Posted: Mon Aug 12, 2024 8:48 am
by sohaib.q
The code below is my network_manager.c is used to deinitialize and initialize the wifi task based on the network_change_counter value. The idea is to switch between wifi interface and observe if there is any memory leakage between a wifi connectivity cycle. I'm having almost 800-900 bytes of memory leakage. The problem seems to be the MQTT component if I do not start the MQTT, there is no memory leakage when we initialize, deinitialize, and again initialize the wifi interface.

network_manager.c
  1. unsigned int network_change_counter = 0;
  2. void network_task(void *pvParameter)
  3. {
  4.     network_change_counter = 0;
  5.     while (1)
  6.     {
  7.         if(flag_wifi_connected)
  8.         {
  9.             network_change_counter++;
  10.             ESP_LOGW(TAG, "Connected Counter: %d.\n", network_change_counter);
  11.             if(network_change_counter > 12 && network_change_counter < 14)
  12.             {
  13.                 ESP_LOGW(TAG, "Deinitializing Wi-Fi mode.\n");
  14.                 // network_change_counter = 0;
  15.                 set_current_network_mode(NETWORK_MODE_NO_NETWORK);
  16.                 // set_change_network_mode_flag();
  17.             }
  18.         }
  19.         if(!flag_wifi_connected && get_current_network_mode() == NETWORK_MODE_NO_NETWORK) // switching to Wi-Fi
  20.         {
  21.             network_change_counter++;
  22.             ESP_LOGW(TAG, "Not connected Counter: %d.\n", network_change_counter);
  23.             if(network_change_counter > 14 && network_change_counter < 16)
  24.             {
  25.                 ESP_LOGW(TAG, "Reinitializing Network mode to: %d.\n", (int)get_current_network_mode());
  26.                 network_change_counter = 0;
  27.                 set_current_network_mode(NETWORK_MODE_ONLY_WIFI);
  28.                 set_change_network_mode_flag();
  29.             }
  30.         }
  31.         if(get_change_network_mode_flag() && !flag_wifi_connected)
  32.         {
  33.             ESP_LOGI(TAG, "Changing Network mode to: %d.\n", (int)get_current_network_mode());
  34.            
  35.             if(get_current_network_mode() == NETWORK_MODE_ONLY_WIFI) // switching to Wi-Fi
  36.             {
  37.                 // xTaskCreatePinnedToCore(&lte_bridge_task, "lte_bridge_task", 1024*4, NULL, 21, NULL, 0);
  38.                 xTaskCreate(&wifi_task, "wifi_task", 1024*6, NULL, 20, NULL);
  39.             }
  40.             reset_change_network_mode_flag();
  41.         }
  42.         vTaskDelay(3000 / portTICK_PERIOD_MS);
  43.     }
  44. }
Below is my wifi_manager.c code

wifi_manager.c
  1. //headers
  2.  
  3. static const char *TAG = "[Wi-Fi]";
  4.  
  5. wifi_config_t wifi_config;
  6. char esp_def_wifi_ssid[SSID_MAX_LEN] = "testWifi";
  7. char esp_def_wifi_pass[PASS_MAX_LEN] = "12345678";
  8.  
  9. #define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK
  10. #define EXAMPLE_H2E_IDENTIFIER ""
  11. #define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
  12.  
  13. wifi_cred_t wifi_cred;
  14. char wifi_ip[16];
  15. bool flag_wifi_connected = false;
  16. bool flag_wifi_cred_changed = false;
  17.  
  18. uint32_t wifi_retry_count = 0;
  19.  
  20. TimerHandle_t wifi_retry_timer = NULL;
  21. static esp_event_handler_instance_t instance_any_id;
  22. static esp_event_handler_instance_t instance_got_ip;
  23. static bool wifi_initialized = false;
  24. extern modem_wifi_config_t s_modem_wifi_config;
  25. extern char hub_id[9];
  26.  
  27. extern esp_err_t mqtt_pause(void);
  28. extern esp_err_t mqtt_resume(void);
  29.  
  30. static void stop_wifi_retry_timer(void)
  31. {
  32.     if (wifi_retry_timer != NULL)
  33.     {
  34.         ESP_LOGI(TAG, "Stopping wifi retry timer.");
  35.         xTimerStop(wifi_retry_timer, 0);
  36.         xTimerDelete(wifi_retry_timer, 0);
  37.         wifi_retry_timer = NULL;
  38.         wifi_retry_count = 0;
  39.     }
  40. }
  41.  
  42. static void wifi_retry_timer_callback(TimerHandle_t xTimer)
  43. {
  44.     if (wifi_retry_count < WIFI_RETRY_MAX_COUNT)
  45.     {
  46.         esp_wifi_connect();
  47.         wifi_retry_count++;
  48.         ESP_LOGI(TAG, "Retry to connect to the AP: %s (Attempt %ld)", wifi_cred.ssid, wifi_retry_count);
  49.     }
  50.     else
  51.     {
  52.         // Switch to LTE mode
  53.         //set LTE mode logic
  54.         stop_wifi_retry_timer();
  55.     }
  56. }
  57.  
  58. static void start_wifi_retry_timer(void)
  59. {
  60.     if (wifi_retry_timer == NULL)
  61.     {
  62.         wifi_retry_timer = xTimerCreate("WifiRetryTimer", pdMS_TO_TICKS(5000), pdTRUE, (void *)0, wifi_retry_timer_callback);
  63.         if (wifi_retry_timer == NULL)
  64.         {
  65.             ESP_LOGE(TAG, "Failed to create retry timer!");
  66.         }
  67.         else
  68.         {
  69.             if (xTimerStart(wifi_retry_timer, 0) != pdPASS)
  70.             {
  71.                 ESP_LOGE(TAG, "Failed to start retry timer!");
  72.             }
  73.             else
  74.             {
  75.                 ESP_LOGI(TAG, "Wi-Fi retry timer created and running successfully.");
  76.             }
  77.         }
  78.     }
  79.     else
  80.     {
  81.         xTimerStart(wifi_retry_timer, 0);
  82.     }
  83. }
  84.  
  85. static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
  86. {
  87.     static bool processing_disconnection = false;
  88.     if (event_base == WIFI_EVENT)
  89.     {
  90.         switch (event_id)
  91.         {
  92.             case WIFI_EVENT_STA_START:
  93.                 esp_wifi_connect();
  94.                 break;
  95.             case WIFI_EVENT_STA_CONNECTED:
  96.                 if(!flag_wifi_connected)
  97.                 {
  98.                     ESP_LOGI(TAG, "Wi-Fi Connected");
  99.                     stop_wifi_retry_timer();
  100.                     flag_wifi_connected = true;
  101.                     processing_disconnection = false;
  102.                 }
  103.                 break;
  104.             case WIFI_EVENT_STA_DISCONNECTED:
  105.                 if (!processing_disconnection) // Process disconnection only if not already processing
  106.                 {
  107.                     ESP_LOGI(TAG, "Wi-Fi Disconnected");
  108.                     flag_wifi_connected = false;
  109.                     processing_disconnection = true;
  110.                     if (get_current_network_mode() == NETWORK_MODE_ONLY_WIFI && wifi_retry_timer == NULL)
  111.                     {
  112.                         start_wifi_retry_timer();
  113.                     }
  114.                     mqtt_pause();
  115.                 }
  116.                 break;
  117.             case WIFI_EVENT_STA_STOP:
  118.                 ESP_LOGI(TAG, "Wi-Fi STA Stopped");
  119.                 processing_disconnection = false;
  120.                 break;
  121.             default:
  122.                 break;
  123.         }
  124.     }
  125.     else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
  126.     {
  127.         ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
  128.         sprintf(wifi_ip, IPSTR, IP2STR(&event->ip_info.ip));
  129.         ESP_LOGI(TAG, "got ip:%s", wifi_ip);
  130.         wifi_retry_count = 0;
  131.         flag_wifi_connected = true;
  132.         processing_disconnection = false;
  133.         mqtt_resume();
  134.     }
  135. }
  136.  
  137. void wifi_init_sta(void)
  138. {
  139.     if (wifi_initialized)
  140.     {
  141.         ESP_LOGW(TAG, "Wi-Fi already initialized, skipping initialization.");
  142.         return;
  143.     }
  144.     // Check if the default Wi-Fi interface already exists
  145.     esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
  146.     if (sta_netif != NULL)
  147.     {
  148.         ESP_LOGW(TAG, "Default Wi-Fi interface already exists");
  149.     }
  150.     else
  151.     {
  152.         // Create the default Wi-Fi interface
  153.         sta_netif = esp_netif_create_default_wifi_sta();
  154.         if (sta_netif == NULL)
  155.         {
  156.             ESP_LOGE(TAG, "Failed to create default Wi-Fi interface");
  157.             return;
  158.         }
  159.     }
  160.  
  161.     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  162.  
  163.     ESP_ERROR_CHECK(esp_wifi_init(&cfg));    
  164.  
  165.     ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
  166.                                                         ESP_EVENT_ANY_ID,
  167.                                                         &wifi_event_handler,
  168.                                                         NULL,
  169.                                                         &instance_any_id));
  170.     ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
  171.                                                         IP_EVENT_STA_GOT_IP,
  172.                                                         &wifi_event_handler,
  173.                                                         NULL,
  174.                                                         &instance_got_ip));
  175.  
  176.     get_wifi_credentials_file(wifi_cred.ssid, wifi_cred.pass);
  177.     ESP_LOGI(TAG, "Got credentails as SSID:%s Password:%s", wifi_cred.ssid, wifi_cred.pass);
  178.     bzero(&wifi_config, sizeof(wifi_config_t));
  179.     memcpy(wifi_config.sta.ssid, wifi_cred.ssid, sizeof(wifi_config.sta.ssid));
  180.     memcpy(wifi_config.sta.password, wifi_cred.pass, sizeof(wifi_config.sta.password));
  181.  
  182.     ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
  183.     ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
  184.     ESP_ERROR_CHECK(esp_wifi_start());
  185.  
  186.     ESP_LOGI(TAG, "wifi_init_sta finished.");
  187.     wifi_initialized = true;
  188. }
  189.  
  190. void wifi_deinit_sta(void)
  191. {
  192.     if (!wifi_initialized)
  193.     {
  194.         ESP_LOGW(TAG, "Wi-Fi not initialized, skipping deinitialization.");
  195.         return;
  196.     }
  197.  
  198.     ESP_LOGE(TAG, "Disconnecting from Wi-Fi");
  199.  
  200.     if (wifi_retry_timer != NULL)
  201.     {
  202.         stop_wifi_retry_timer();
  203.     }
  204.    
  205.     esp_wifi_disconnect();
  206.     esp_wifi_stop();
  207.     esp_wifi_deinit();
  208.  
  209.     ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
  210.     ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
  211.    
  212.     // Destroy default Wi-Fi netif
  213.     esp_netif_t *netifConf = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
  214.     if (netifConf != NULL)
  215.     {
  216.         esp_netif_destroy_default_wifi(netifConf);
  217.     }
  218.     // Deinitialize the network interface
  219.     // esp_netif_deinit();
  220.     wifi_initialized = false;
  221. }
  222.  
  223. void wifi_task(void *pvParameter)
  224. {
  225.     ESP_LOGI(TAG, "Wi-Fi task created successfully");
  226.     wifi_init_sta();
  227.  
  228.     while (1)
  229.     {
  230.         if (get_current_network_mode() != NETWORK_MODE_ONLY_WIFI)
  231.         {
  232.             wifi_deinit_sta();
  233.             break;
  234.         }
  235.         vTaskDelay(1000 / portTICK_PERIOD_MS);
  236.     }
  237.     ESP_LOGW(TAG, "Deleting wifi_task");
  238.     // Delete the task
  239.     vTaskDelete(NULL);
  240. }

Below is the code for mqtt_manager.c which is being initialized in the start using mqtt_app_start function

mqtt_manager.c
  1. // headers
  2.  
  3. static const char *TAG = "[MQTT_MANAGER]";
  4.  
  5. esp_mqtt_client_handle_t client = NULL;
  6.  
  7.  
  8. mqtt_topic_t hub_sub_topic_request;
  9. mqtt_topic_t hub_pub_topic_event;
  10.  
  11. extern const uint8_t client_cert_pem_start[] asm("_binary_client_crt_start");
  12. extern const uint8_t client_cert_pem_end[] asm("_binary_client_crt_end");
  13. extern const uint8_t client_key_pem_start[] asm("_binary_client_key_start");
  14. extern const uint8_t client_key_pem_end[] asm("_binary_client_key_end");
  15. extern const uint8_t server_cert_pem_start[] asm("_binary_mosquitto_org_crt_start");
  16. extern const uint8_t server_cert_pem_end[] asm("_binary_mosquitto_org_crt_end");
  17.  
  18. char *json_resp;
  19. char *json_err;
  20.  
  21. static void log_error_if_nonzero(const char *message, int error_code)
  22. {
  23.     if (error_code != 0) {
  24.         ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
  25.     }
  26. }
  27.  
  28. esp_err_t mqtt_pause(void)
  29. {
  30.     return esp_mqtt_client_stop(client);
  31. }
  32.  
  33. esp_err_t mqtt_resume(void)
  34. {
  35.     return esp_mqtt_client_start(client);
  36. }
  37.  
  38. static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
  39. {
  40.     ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
  41.  
  42.     esp_mqtt_event_handle_t event = event_data;
  43.     esp_mqtt_client_handle_t client = event->client;
  44.  
  45.     int msg_id = -1;
  46.  
  47.     switch ((esp_mqtt_event_id_t)event_id)
  48.     {
  49.     case MQTT_EVENT_CONNECTED:
  50.         ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
  51.  
  52.         msg_id = esp_mqtt_client_subscribe(client, hub_sub_topic_request.topic, 0);
  53.         ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
  54.  
  55.         msg_id = esp_mqtt_client_publish(client, hub_pub_topic_event.topic, get_hub_online_string(), 0, 0, 0);
  56.         ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
  57.  
  58.         break;
  59.  
  60.     case MQTT_EVENT_DISCONNECTED:
  61.         ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
  62.         break;
  63.  
  64.     case MQTT_EVENT_SUBSCRIBED:
  65.         ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
  66.         break;
  67.  
  68.     case MQTT_EVENT_UNSUBSCRIBED:
  69.         ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
  70.         break;
  71.  
  72.     case MQTT_EVENT_PUBLISHED:
  73.         ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
  74.         break;
  75.  
  76.     case MQTT_EVENT_DATA:
  77.         ESP_LOGI(TAG, "MQTT_EVENT_DATA");
  78.         break;
  79.  
  80.     case MQTT_EVENT_ERROR:
  81.         ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
  82.         if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT)
  83.         {
  84.             log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
  85.             log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
  86.             log_error_if_nonzero("captured as transport's socket errno",  event->error_handle->esp_transport_sock_errno);
  87.             ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
  88.  
  89.         }
  90.         break;
  91.  
  92.     default:
  93.         ESP_LOGI(TAG, "Other event id:%d", event->event_id);
  94.         break;
  95.     }
  96. }
  97.  
  98. void mqtt_app_start(char *hub_id)
  99. {
  100.     esp_err_t err = esp_netif_init();
  101.     if (err != ESP_OK)
  102.     {
  103.         ESP_LOGE(TAG, "Failed to initialize TCP/IP stack: %s", esp_err_to_name(err));
  104.         return;
  105.     }
  106.     // Create the default event loop
  107.     err = esp_event_loop_create_default();
  108.     if (err != ESP_OK)
  109.     {
  110.         ESP_LOGE(TAG, "Failed to create default event loop: %s", esp_err_to_name(err));
  111.         esp_netif_deinit();
  112.         return;
  113.     }
  114.    
  115.     ESP_LOGI(TAG, "Starting MQTT process");
  116.     esp_err_t esp_mqtt_err;
  117.     sprintf(hub_sub_topic_request.topic,"header/%s/hub/request",hub_id);
  118.  
  119.     sprintf(hub_pub_topic_event.topic,"header/%s/hub/event",hub_id);
  120.  
  121.  
  122.     const esp_mqtt_client_config_t mqtt_cfg =
  123.     {
  124.         .broker.address.uri = "mqtts://urlxxxx.iot.us-east-1.amazonaws.com:8883",
  125.         .broker.verification.certificate = (const char *)server_cert_pem_start,
  126.         .credentials =
  127.         {
  128.             .authentication =
  129.             {
  130.                 .certificate = (const char *)client_cert_pem_start,
  131.                 .key = (const char *)client_key_pem_start,
  132.             },
  133.         }
  134.     };
  135.  
  136.     client = esp_mqtt_client_init(&mqtt_cfg);
  137.     if (client == NULL)
  138.     {
  139.         ESP_LOGE(TAG, "Failed to initialize MQTT client");
  140.         return;
  141.     }
  142.     // The last argument may be used to pass data to the event handler, in this example mqtt_event_handler
  143.     esp_mqtt_err = esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
  144.     if (esp_mqtt_err != ESP_OK)
  145.     {
  146.         ESP_LOGE(TAG, "Failed to register MQTT event handler: %s", esp_err_to_name(esp_mqtt_err));
  147.     }
  148.     /* esp_mqtt_err = esp_mqtt_client_start(client);
  149.     if (esp_mqtt_err != ESP_OK)
  150.     {
  151.         ESP_LOGE(TAG, "Failed to start MQTT client: %s", esp_err_to_name(esp_mqtt_err));
  152.     }*/
  153. }
I'm printing the Internal Free heap size using esp_get_free_internal_heap_size() and every time I get connected to the MQTT broker and publish a message, there is a decrease in available heap size by almost 800-900 bytes.