[SOLVED] ESP32 - How to switch from AP to STA and vice versa

filo_gr
Posts: 110
Joined: Wed Jul 28, 2021 12:25 pm
Location: Italy

[SOLVED] ESP32 - How to switch from AP to STA and vice versa

Postby filo_gr » Fri Jul 30, 2021 1:03 pm

Hello community,

I'm trying to make a code for ESP32 where I can switch from WiFi Access Point mode to WiFi Station, with the opportunity to switch back from WiFi Station to WiFi Access Point.
I highlight the fact that I don't want to use the AP+STA modality, but I want only one active at a time.

I've been able to make the code for switching from AP to STA. However if I try to switch from STA to AP I obtain an error and the ESP reboots.
Indeed the problem is the fact I use, inside the function for AP initialization:
  1. esp_netif_t* wifiAP = esp_netif_create_default_wifi_ap();
that gives me an assert error because, inside itself, it uses esp_netif_new.
Same problem I think would happen if, from AP to STA, I call again
  1. esp_netif_create_default_wifi_sta();
I don't understand what is the best solution to make it work. :?:

Regards,
Filippo
Last edited by filo_gr on Wed Aug 04, 2021 7:12 am, edited 1 time in total.
Filippo

filo_gr
Posts: 110
Joined: Wed Jul 28, 2021 12:25 pm
Location: Italy

Re: ESP32 - How to switch from AP to STA and vice versa

Postby filo_gr » Mon Aug 02, 2021 6:27 am

When I want to initialize and start the WiFi Access Point I use this piece of code:
  1. void wifi_init_softap(void){
  2.     esp_netif_ip_info_t ipInfo;
  3.     esp_netif_t* wifiAP = esp_netif_create_default_wifi_ap();
  4.     IP4_ADDR(&ipInfo.ip, 192,168,2,1);
  5.     IP4_ADDR(&ipInfo.gw, 192,168,2,1);
  6.     IP4_ADDR(&ipInfo.netmask, 255,255,255,0);
  7.  
  8.     esp_netif_dhcps_stop(wifiAP);
  9.     esp_netif_set_ip_info(wifiAP, &ipInfo);
  10.     esp_netif_dhcps_start(wifiAP);
  11.  
  12.     ESP_LOGI(TAG, "IP: " IPSTR, IP2STR(&ipInfo.ip));
  13.     ESP_LOGI(TAG, "GW: " IPSTR, IP2STR(&ipInfo.gw));
  14.     ESP_LOGI(TAG, "Mask: " IPSTR, IP2STR(&ipInfo.netmask));
  15.  
  16.     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  17.     ESP_ERROR_CHECK(esp_wifi_init(&cfg));
  18.  
  19.  
  20.     ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
  21.     wifi_config_t wifi_config = {
  22.         .ap = {
  23.             .ssid = EXAMPLE_ESP_WIFI_SSID,
  24.             .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
  25.             .password = EXAMPLE_ESP_WIFI_PASS,
  26.             .max_connection = EXAMPLE_MAX_STA_CONN,
  27.             .authmode = WIFI_AUTH_WPA_WPA2_PSK
  28.         },
  29.     };
  30.  
  31.     if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
  32.         wifi_config.ap.authmode = WIFI_AUTH_OPEN;
  33.     }
  34.                        
  35.     ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
  36.     ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
  37.                            
  38.  
  39.     ESP_ERROR_CHECK(esp_wifi_start());
  40.     ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);      
  41. }
It works correctly.
However I assume I have the functionality that permit the switch from access point to station.
Here the code I used to initialize and start my WiFi station (NOTE: by doing this way, the active AP will deactivate itself):
  1. esp_err_t make_sta_handler(httpd_req_t *req){
  2.     ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
  3.     s_wifi_event_group = xEventGroupCreate();
  4.     ESP_ERROR_CHECK(esp_wifi_stop());
  5.     //ESP_ERROR_CHECK(esp_netif_init());
  6.     //ESP_ERROR_CHECK(esp_event_loop_create_default());
  7.  
  8.     esp_netif_create_default_wifi_sta();
  9.     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  10.     ESP_ERROR_CHECK(esp_wifi_init(&cfg));
  11.  
  12.     esp_event_handler_instance_t instance_any_id;
  13.     esp_event_handler_instance_t instance_got_ip;
  14.  
  15.     ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
  16.                     &event_handler, NULL, &instance_any_id));
  17.     ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
  18.                     &event_handler, NULL, &instance_got_ip));
  19.  
  20.     wifi_config_t wifi_config = {
  21.         .sta = {
  22.             .ssid = ESP_WIFI_SSID,
  23.             .password = ESP_WIFI_PASS,
  24.             /* Setting a password implies station will connect to all security modes including WEP/WPA.
  25.              * However these modes are deprecated and not advisable to be used. Incase your Access point
  26.              * doesn't support WPA2, these mode can be enabled by commenting below line */
  27.             .threshold.authmode = WIFI_AUTH_WPA2_PSK,
  28.             .pmf_cfg = {
  29.                 .capable = true,
  30.                 .required = false
  31.             },
  32.         },
  33.     };
  34.  
  35.     ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
  36.     ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
  37.     ESP_ERROR_CHECK(esp_wifi_start());
  38.     ESP_LOGI(TAG, "wifi_init_sta finished.");
  39.  
  40.     EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE,
  41.             pdFALSE, portMAX_DELAY);
  42.     /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
  43.      * happened. */
  44.     if (bits & WIFI_CONNECTED_BIT) {
  45.         ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", ESP_WIFI_SSID, ESP_WIFI_PASS);
  46.     }
  47.     else if (bits & WIFI_FAIL_BIT) {
  48.         ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", ESP_WIFI_SSID, ESP_WIFI_PASS);
  49.     }
  50.     else {
  51.         ESP_LOGE(TAG, "UNEXPECTED EVENT");
  52.     }
  53.  
  54.     /* The event will not be processed after unregister */
  55.     ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
  56.     ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
  57.     vEventGroupDelete(s_wifi_event_group);
  58.     return ESP_OK;
  59. }
Let's suppose I want to switch back to AP mode, and then to STA mode, and so on all the times I want and I need.
I'm sure I don't need to initialize always all the protocols (in fact I obtain errors).
On the other hand, I don't understand what exactly I have to do.
My question is: What are the pieces of code I don't need when switching the modalities?
Filippo

Moriki
Posts: 6
Joined: Sun May 02, 2021 6:31 pm

Re: ESP32 - How to switch from AP to STA and vice versa

Postby Moriki » Tue Aug 03, 2021 5:59 am

I am not sure this is what you are searching and if it is the most accurate way, but this is the logic I use to be able to change modes in esp.

My Init proccess (regardless of sta or ap):
esp_netif_init
esp_event_loop_create_default
esp_wifi_init
esp_wifi_set_mode(WIFI_MODE_NULL)
esp_event_handler_instance_register
esp_wifi_set_storage(WIFI_STORAGE_RAM) <---- not mandatory

My AP start:
if (!m_apNetif)
m_apNetif = esp_netif_create_default_wifi_ap();

esp_wifi_set_mode(WIFI_MODE_AP)
esp_wifi_set_config(WIFI_IF_AP, &ap_config)
esp_wifi_start();

My STA start:
if (!m_staNetif)
m_staNetif = esp_netif_create_default_wifi_sta();
esp_wifi_set_mode(WIFI_MODE_STA)
esp_wifi_set_config(WIFI_IF_STA, &config)
esp_wifi_start()
*After that, in the event loop when you get STA_START event you should call: esp_wifi_connect();*

If I want to change a mode, I need to stop first the previous mode.
To stop the connections of each state before switching to the other mode I use -
esp_wifi_disconnect() //<----- ONLY IF YOU WERE STA, NOT NEEDED WHEN STOPPING AP
esp_wifi_stop();
esp_wifi_set_mode(WIFI_MODE_NULL);

After that you can call either of the start functions of sta or ap again to connect to the necessary mode
Hopefully it helps.

filo_gr
Posts: 110
Joined: Wed Jul 28, 2021 12:25 pm
Location: Italy

Re: ESP32 - How to switch from AP to STA and vice versa

Postby filo_gr » Tue Aug 03, 2021 10:12 am

Thank you very much @Moriki !!!
I studied your solution and finally I've made it work! :D
I don't know if it's exactly how you would implement it, however it switches quickly betweens the two modalities (I use UART commands in order to control which mode must be active).
Also, if AP is active but I select AP again, it restarts the AP without any crash (STA mode does the same).
I share with the community the parts of code I wrote to make it work.
-- Part of code inside the app_main (it enables AP by default) --
  1.     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  2.     ESP_ERROR_CHECK(esp_wifi_init(&cfg));
  3.     esp_wifi_set_mode(WIFI_MODE_NULL);
  4.     ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
  5.                     &wifi_event_handler, NULL, &instance_any_id));
  6.     ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
  7.                     &wifi_event_handler, NULL, &instance_got_ip));
  8.     esp_wifi_set_storage(WIFI_STORAGE_RAM);
  9.     wifiAP = esp_netif_create_default_wifi_ap();
  10.     esp_netif_create_default_wifi_sta();
  11.     from_sta_to_ap();
The code that enables the access point AP checks also if the station mode STA is active, so it deactivates this modality, then it proceeds enabling the access point.
-- from_sta_to_ap (uses the global variable ap_sta to understand the previous state) --
  1. void from_sta_to_ap(void){
  2.     printf("## Entering from_sta_to_ap.\n");
  3.     esp_netif_ip_info_t ipInfo;
  4.     if(ap_sta == 1){
  5.         ESP_ERROR_CHECK(esp_wifi_disconnect());
  6.         ESP_ERROR_CHECK(esp_wifi_stop());
  7.         ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
  8.     }
  9.     IP4_ADDR(&ipInfo.ip, 192,168,2,1);
  10.     IP4_ADDR(&ipInfo.gw, 192,168,2,1);
  11.     IP4_ADDR(&ipInfo.netmask, 255,255,255,0);
  12.     esp_netif_dhcps_stop(wifiAP);
  13.     esp_netif_set_ip_info(wifiAP, &ipInfo);
  14.     esp_netif_dhcps_start(wifiAP);
  15.     ESP_LOGI(TAG, "IP: " IPSTR, IP2STR(&ipInfo.ip));
  16.     ESP_LOGI(TAG, "GW: " IPSTR, IP2STR(&ipInfo.gw));
  17.     ESP_LOGI(TAG, "Mask: " IPSTR, IP2STR(&ipInfo.netmask));
  18.     wifi_config_t wifi_config = {
  19.         .ap = {
  20.             .ssid = EXAMPLE_ESP_WIFI_SSID,
  21.             .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
  22.             .password = EXAMPLE_ESP_WIFI_PASS,
  23.             .max_connection = EXAMPLE_MAX_STA_CONN,
  24.             .authmode = WIFI_AUTH_WPA_WPA2_PSK
  25.         },
  26.     };
  27.     if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
  28.         wifi_config.ap.authmode = WIFI_AUTH_OPEN;
  29.     }
  30.     ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
  31.     ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
  32.     ESP_ERROR_CHECK(esp_wifi_start());
  33.     ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
  34.     ap_sta = 0;
  35. }
This code that deactivates the access point AP (if active) and then enables the STA mode.
-- from_ap_to_sta (uses the global variable ap_sta to understand the previous state) --
  1. void from_ap_to_sta(void){
  2. printf("## Entering from_ap_to_sta.\n");
  3.     if(ap_sta == 0){
  4.         ESP_ERROR_CHECK(esp_wifi_stop());
  5.         ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
  6.     }
  7.     s_wifi_event_group = xEventGroupCreate();
  8.     wifi_config_t wifi_config = {
  9.         .sta = {
  10.             .ssid = ESP_WIFI_SSID,
  11.             .password = ESP_WIFI_PASS,
  12.             .threshold.authmode = WIFI_AUTH_WPA2_PSK,
  13.             .pmf_cfg = {
  14.                 .capable = true,
  15.                 .required = false
  16.             },
  17.         },
  18.     };
  19.     ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
  20.     ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
  21.     ESP_ERROR_CHECK(esp_wifi_start());
  22.     EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE,
  23.             pdFALSE, portMAX_DELAY);
  24.     if (bits & WIFI_CONNECTED_BIT) {
  25.         ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", ESP_WIFI_SSID, ESP_WIFI_PASS);
  26.     }
  27.     else if (bits & WIFI_FAIL_BIT) {
  28.         ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", ESP_WIFI_SSID, ESP_WIFI_PASS);
  29.     }
  30.     else {
  31.         ESP_LOGE(TAG, "UNEXPECTED EVENT");
  32.     }
  33.     vEventGroupDelete(s_wifi_event_group);
  34.     ap_sta = 1;
  35. }
I won't publish the event handler because it is sufficient to merge the handlers of the simple access point example and station example.

Regards,
Filippo
Filippo

Moriki
Posts: 6
Joined: Sun May 02, 2021 6:31 pm

Re: ESP32 - How to switch from AP to STA and vice versa

Postby Moriki » Tue Aug 03, 2021 12:27 pm

Glad to be of help :) :)

Who is online

Users browsing this forum: Majestic-12 [Bot] and 69 guests