Conectividade WiFi e Networking 📶
Configuração e Gerenciamento WiFi
O WiFi representa funcionalidade essencial para maioria das aplicações IoT modernas, permitindo conectividade sem fio com internet e redes locais. O ESP32 integra pilha WiFi completa com suporte para 802.11 b/g/n, oferecendo performance adequada para streaming de dados, atualizações OTA e comunicação em tempo real com servidores cloud.
O ESP-IDF oferece API WiFi abrangente que abstrai complexidade do hardware RF e protocolos de baixo nível, expondo interface de alto nível para conectar redes, gerenciar credenciais e monitorar status de conexão. O driver WiFi opera como componente do sistema gerenciado por event loop, disparando eventos quando mudanças importantes ocorrem como conexão estabelecida ou perda de link.
A configuração WiFi envolve vários estágios incluindo inicialização do hardware, configuração de modo operacional, especificação de credenciais e estabelecimento de conexão. Cada estágio requer chamadas de API específicas em ordem correta, e o sistema de eventos permite que sua aplicação reaja apropriadamente a mudanças no estado da conexão.
⚠️ Modos de Operação WiFi
O ESP32 suporta três modos principais de operação WiFi que determinam como o dispositivo interage com redes wireless. Compreender estes modos e quando usar cada um é fundamental para arquitetar aplicações IoT efetivas.
O modo Station conecta o ESP32 a access point existente como qualquer dispositivo WiFi convencional. Este é o modo mais comum para aplicações IoT onde dispositivo precisa conectar à rede doméstica ou corporativa para acessar internet. No modo Station, o ESP32 recebe endereço IP do roteador via DHCP e pode comunicar com outros dispositivos na rede.
O modo Access Point transforma o ESP32 em ponto de acesso ao qual outros dispositivos podem conectar. Este modo é útil para configuração inicial de dispositivos IoT onde usuário conecta smartphone diretamente ao ESP32 para fornecer credenciais WiFi da rede principal. Também é valioso para criar redes ad-hoc entre dispositivos ESP32 sem infraestrutura externa.
O modo Station mais Access Point permite que ESP32 opere simultaneamente nos dois modos, conectando a rede existente enquanto oferece seu próprio access point. Este modo híbrido facilita configuração remota e update de dispositivos já implantados sem perder conectividade com rede principal.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
static const char *TAG = "WIFI_EXAMPLE";
// Credenciais WiFi - em produção, armazene de forma segura
#define WIFI_SSID "SuaRedeWiFi"
#define WIFI_PASS "SuaSenha"
#define WIFI_MAX_RETRY 5
// Event group para sinalizar quando conectado
static EventGroupHandle_t s_wifi_event_group;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static int s_retry_num = 0;
/**
* Handler de eventos WiFi
*
* Esta função é chamada automaticamente pelo sistema de eventos
* quando ocorrem mudanças no estado do WiFi
*/
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
// WiFi iniciado, tentar conectar
ESP_LOGI(TAG, "WiFi iniciado, conectando...");
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
// Desconectado, tentar reconectar se não excedeu limite
if (s_retry_num < WIFI_MAX_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "Tentando reconectar... (%d/%d)",
s_retry_num, WIFI_MAX_RETRY);
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
ESP_LOGE(TAG, "Falha ao conectar após %d tentativas", WIFI_MAX_RETRY);
}
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
// Obteve endereço IP, conexão estabelecida
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "Conectado! IP obtido: " IPSTR,
IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
/**
* Inicializar WiFi em modo Station
*
* Configura todos os componentes necessários e inicia conexão
*/
esp_err_t wifi_init_sta(void)
{
ESP_LOGI(TAG, "Inicializando WiFi em modo Station");
// Criar event group para sincronização
s_wifi_event_group = xEventGroupCreate();
// Inicializar stack TCP/IP
ESP_ERROR_CHECK(esp_netif_init());
// Criar event loop padrão
ESP_ERROR_CHECK(esp_event_loop_create_default());
// Criar interface de rede padrão para station
esp_netif_create_default_wifi_sta();
// Inicializar WiFi com configuração padrão
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// Registrar handlers de eventos
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&wifi_event_handler,
NULL,
&instance_got_ip));
// Configurar parâmetros de conexão
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASS,
// Configurações de segurança e otimização
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.capable = true,
.required = false
},
},
};
// Configurar modo e aplicar configuração
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "WiFi configurado, aguardando conexão...");
// Aguardar até conectar ou falhar
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "Conectado ao AP SSID:%s", WIFI_SSID);
return ESP_OK;
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGE(TAG, "Falha ao conectar ao AP SSID:%s", WIFI_SSID);
return ESP_FAIL;
} else {
ESP_LOGE(TAG, "Evento inesperado");
return ESP_FAIL;
}
}
/**
* Obter informações sobre conexão WiFi atual
*
* Útil para monitoramento e diagnóstico
*/
void wifi_print_connection_info(void)
{
wifi_ap_record_t ap_info;
esp_err_t ret = esp_wifi_sta_get_ap_info(&ap_info);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "=== Informações da Conexão ===");
ESP_LOGI(TAG, "SSID: %s", ap_info.ssid);
ESP_LOGI(TAG, "Canal: %d", ap_info.primary);
ESP_LOGI(TAG, "RSSI: %d dBm", ap_info.rssi);
ESP_LOGI(TAG, "Autenticação: %d", ap_info.authmode);
ESP_LOGI(TAG, "MAC do AP: %02x:%02x:%02x:%02x:%02x:%02x",
ap_info.bssid[0], ap_info.bssid[1], ap_info.bssid[2],
ap_info.bssid[3], ap_info.bssid[4], ap_info.bssid[5]);
// Interpretar força do sinal
if (ap_info.rssi > -50) {
ESP_LOGI(TAG, "Qualidade do sinal: Excelente");
} else if (ap_info.rssi > -60) {
ESP_LOGI(TAG, "Qualidade do sinal: Boa");
} else if (ap_info.rssi > -70) {
ESP_LOGI(TAG, "Qualidade do sinal: Regular");
} else {
ESP_LOGI(TAG, "Qualidade do sinal: Fraca");
}
} else {
ESP_LOGW(TAG, "Não foi possível obter informações do AP");
}
// Obter endereço IP atual
esp_netif_ip_info_t ip_info;
esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
if (netif && esp_netif_get_ip_info(netif, &ip_info) == ESP_OK) {
ESP_LOGI(TAG, "Endereço IP: " IPSTR, IP2STR(&ip_info.ip));
ESP_LOGI(TAG, "Máscara de rede: " IPSTR, IP2STR(&ip_info.netmask));
ESP_LOGI(TAG, "Gateway: " IPSTR, IP2STR(&ip_info.gw));
}
}
/**
* Escanear redes WiFi disponíveis
*
* Útil para descobrir redes e avaliar qualidade de sinal
*/
void wifi_scan_networks(void)
{
ESP_LOGI(TAG, "Iniciando scan de redes WiFi...");
// Configurar parâmetros de scan
wifi_scan_config_t scan_config = {
.ssid = NULL,
.bssid = NULL,
.channel = 0,
.show_hidden = true,
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
.scan_time.active.min = 100,
.scan_time.active.max = 300,
};
esp_err_t ret = esp_wifi_scan_start(&scan_config, true);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Falha ao iniciar scan: %s", esp_err_to_name(ret));
return;
}
// Obter número de redes encontradas
uint16_t num_aps = 0;
esp_wifi_scan_get_ap_num(&num_aps);
if (num_aps == 0) {
ESP_LOGW(TAG, "Nenhuma rede encontrada");
return;
}
ESP_LOGI(TAG, "%d rede(s) encontrada(s)", num_aps);
// Alocar buffer para resultados
wifi_ap_record_t *ap_records = malloc(sizeof(wifi_ap_record_t) * num_aps);
if (ap_records == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória para scan");
return;
}
// Obter resultados do scan
esp_wifi_scan_get_ap_records(&num_aps, ap_records);
// Exibir informações de cada rede
ESP_LOGI(TAG, "=== Redes Disponíveis ===");
for (int i = 0; i < num_aps; i++) {
ESP_LOGI(TAG, "%2d: SSID: %-32s Canal: %2d RSSI: %3d dBm Auth: %d",
i + 1,
ap_records[i].ssid,
ap_records[i].primary,
ap_records[i].rssi,
ap_records[i].authmode);
}
free(ap_records);
}
/**
* Configurar WiFi Power Save
*
* Economizar energia é essencial para dispositivos IoT alimentados por bateria.
* O ESP32 oferece vários modos de economia de energia WiFi.
*/
esp_err_t wifi_configure_power_save(wifi_ps_type_t ps_mode)
{
esp_err_t ret = esp_wifi_set_ps(ps_mode);
if (ret == ESP_OK) {
const char *mode_str[] = {"NONE", "MIN_MODEM", "MAX_MODEM"};
ESP_LOGI(TAG, "Power save configurado: %s",
mode_str[ps_mode < 3 ? ps_mode : 0]);
} else {
ESP_LOGE(TAG, "Falha ao configurar power save: %s",
esp_err_to_name(ret));
}
return ret;
}
/**
* Monitorar qualidade da conexão WiFi
*
* Task que monitora continuamente força do sinal e reconecta se necessário
*/
void wifi_monitoring_task(void *pvParameters)
{
ESP_LOGI(TAG, "Task de monitoramento WiFi iniciada");
const int RSSI_THRESHOLD = -75; // Reconectar se sinal ficar muito fraco
int weak_signal_count = 0;
while (1) {
wifi_ap_record_t ap_info;
esp_err_t ret = esp_wifi_sta_get_ap_info(&ap_info);
if (ret == ESP_OK) {
ESP_LOGD(TAG, "RSSI atual: %d dBm", ap_info.rssi);
// Verificar qualidade do sinal
if (ap_info.rssi < RSSI_THRESHOLD) {
weak_signal_count++;
ESP_LOGW(TAG, "Sinal fraco detectado (%d/3): %d dBm",
weak_signal_count, ap_info.rssi);
// Se sinal fraco persistir, tentar reconectar
if (weak_signal_count >= 3) {
ESP_LOGW(TAG, "Sinal persistentemente fraco, reconectando...");
esp_wifi_disconnect();
vTaskDelay(pdMS_TO_TICKS(1000));
esp_wifi_connect();
weak_signal_count = 0;
}
} else {
weak_signal_count = 0;
}
} else {
ESP_LOGW(TAG, "WiFi desconectado, aguardando reconexão...");
weak_signal_count = 0;
}
vTaskDelay(pdMS_TO_TICKS(10000)); // Verificar a cada 10 segundos
}
}
/**
* Configurar IP estático ao invés de DHCP
*
* Útil para servidores ou dispositivos que precisam IP fixo
*/
esp_err_t wifi_set_static_ip(const char *ip_addr, const char *gateway,
const char *netmask)
{
ESP_LOGI(TAG, "Configurando IP estático: %s", ip_addr);
esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
if (netif == NULL) {
ESP_LOGE(TAG, "Interface de rede não encontrada");
return ESP_FAIL;
}
// Parar DHCP client
esp_netif_dhcpc_stop(netif);
// Configurar IP estático
esp_netif_ip_info_t ip_info;
ip_info.ip.addr = ipaddr_addr(ip_addr);
ip_info.gw.addr = ipaddr_addr(gateway);
ip_info.netmask.addr = ipaddr_addr(netmask);
esp_err_t ret = esp_netif_set_ip_info(netif, &ip_info);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "IP estático configurado com sucesso");
} else {
ESP_LOGE(TAG, "Falha ao configurar IP estático: %s",
esp_err_to_name(ret));
}
return ret;
}
void app_main(void)
{
ESP_LOGI(TAG, "Demonstrando conectividade WiFi");
// Inicializar NVS (necessário para WiFi)
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// Fazer scan de redes disponíveis (opcional)
// Necessário inicializar WiFi em modo NULL primeiro para scan
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
wifi_scan_networks();
// Agora conectar à rede
ret = wifi_init_sta();
if (ret == ESP_OK) {
// Exibir informações da conexão
wifi_print_connection_info();
// Configurar power save para economizar energia
wifi_configure_power_save(WIFI_PS_MIN_MODEM);
// Criar task de monitoramento
xTaskCreate(wifi_monitoring_task, "WiFi_Monitor",
3072, NULL, 3, NULL);
ESP_LOGI(TAG, "Sistema WiFi pronto para uso");
} else {
ESP_LOGE(TAG, "Falha ao conectar WiFi");
}
}