ESP32 (5) – Wifi scanner

luca 09/01/2017 3

The main feature of the esp32 chip, as it was for its predecessor esp8266, is for sure the ability to connect to wifi networks. I’ve already blogged in a previous article about the different standards (802.11 b/g/n) and security methods (WEP, WPA-PSK…) the chip supports; today I’m going to explain how to develop a program to scan for available wifi networks.

The complete program is available in my Github repository; let’s comment the source code.

As we know, every program using the esp-idf framework is executed starting from the app_main() method. This method starts initializing the tcpip stack and the wifi event handler:

tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
ESP_ERROR_CHECK is a handy macro, defined in esp_err.h, to check the result of the different framework methods. If a call returns the constant ESP_OK, the execution of the program can proceed; if not the program is stopped and the line in error is displayed on the serial output.

The esp-idf wifi stack requires a method (= event handler) that is called every time an event related to the wifi interface is triggered (for example the connection to a new network…). We’ll talk in a future tutorial about event handling, for now it’s enough to define an empty handler method:

static esp_err_t event_handler(void *ctx, system_event_t *event)
{
  return ESP_OK;
}

The program continues configuring, initializing and starting the wifi stack:

wifi_init_config_t wifi_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_config));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());

You can create a default configuration with the WIFI_INIT_CONFIG_DEFAULT() macro and start the wifi interface in station mode with the constant WIFI_MODE_STA. Station mode is when the interface acts as a “client”, to connect to an access point.

Now you can configure and start the scan process:

wifi_scan_config_t scan_config = {
	.ssid = 0,
	.bssid = 0,
	.channel = 0,
        .show_hidden = true
};
ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, true));

Using the scan_config variable you can configure some filters the scanning process will use (for example scan only a given channel) and ask to display or not the access points with hidden SSID. A zero value for each field means ALL (= no filter).

The scanning process can be executed in blocking (true) or non blocking (false) mode changing the second parameter of the function esp_wifi_scan_start. In this example I’m using the blocking mode: program execution is halted until the scan is completed.

When the scan is complete, you can obtain the list of the detected networks:

uint16_t ap_num = MAX_APs;
wifi_ap_record_t ap_records[MAX_APs];
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_num, ap_records));

The esp_wifi_scan_get_ap_records method returns an array of wifi_ap_record_t elements. You have to reserve some memory space to store that array, defining the maximum number of elements you want to retrieve. In my program, I defined therefore the MAX_APs constant:

#define MAX_APs 20
It may sound strange to pass the ap_num variable by reference to the esp_wifi_scan_get_ap_records method. The reason is that the method uses the variable in two ways (inout): as input to find the max capacity of the array passed as the second parameter and as output to return the effective number of networks found and stored in the array.

You can now print on the serial connection the details of the networks found:

printf("Found %d access points:\n", ap_num);
for(int i = 0; i < ap_num; i++)
	printf("%32s | %7d | %4d | %12s\n", 
	(char *)ap_records[i].ssid, ap_records[i].primary, ap_records[i].rssi,
	getAuthModeName(ap_records[i].authmode));

At the end, create an empty task to avoid a continuous reset of the chip:

xTaskCreate(&loop_task, "loop_task", 2048, NULL, 5, NULL);
[...]
void loop_task(void *pvParameter) {
    while(1) { 
        vTaskDelay(1000 / portTICK_RATE_MS);		
    }
}

During the program compilation, remember to activate the wifi module in the menuconfig (Component config – ESP32-specific config):

esp32-wifi01

Here’s the output of the program:

esp-scan02

3 Comments »

  1. Michele 11/01/2017 at 10:02 - Reply

    Salve, Un piccolo dubbio , sulla funzione che crea un nuovo task:

    xTaskCreate(&loop_task, “loop_task”, 2048, NULL, 5, NULL);

    2048 è lo usStackDepth, mi sono spempre chiesto come va dimensionato?
    Bisogna considerare tutte la variabili dentro il task “loop_task”, ma bisogna anche considerare variabili esterne dichiarate globali e che vengono usate all’interno di “loop_task”?

  2. Luciano Veronese 15/01/2017 at 12:43 - Reply

    Articolo molto interessante Luca, grazie!
    Oltre a questa funzione, sarebbe possibile verificare se un determinato MAC address è collegato a una specifica rete wifi ?
    Questo permetterebbe di verificare anche da remoto se un determinato dispositivo è fisicamente presente nel raggio della rete wifi.

    Esempi?

    Grazie 1000
    Luciano

    • luca 16/01/2017 at 08:53 - Reply

      Ciao Luciano, per sapere se un MAC è collegato ad una rete wifi dovresti interrogare l’access point che gestisce quella wifi o – solo se il device fa “traffico” – intercettarlo. Non mi pare però che il chip esp32 attualmente consenta di attivare la modalità “promiscua” per analizzare il traffico, mi dispiace

Leave A Response »

This website uses cookies to ensure you get the best experience on our website maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.

Chiudi