esp32-wifi-manager/main/esp32-wifi-manager.c

328 lines
8.6 KiB
C

#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_event_loop.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "driver/spi_common.h"
#include "driver/spi_master.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "esp32-wifi-manager.h"
#define MAX_ESSID (32)
#define MAX_PASSWORD (64)
static const char *TAG = "WM";
static EventGroupHandle_t wm_event_group;
nvs_handle nvs;
typedef struct wifi_manager_ap_info {
char ssid[MAX_ESSID];
char password[MAX_PASSWORD];
} wifi_manager_ap_info_t;
typedef struct ap_store_base {
int8_t last;
uint8_t count;
uint32_t magic;
wifi_manager_ap_info_t aps[CONFIG_WIFI_MANAGER_MAX_AP];
} ap_store_t;
ap_store_t ap_store;
EventGroupHandle_t wifi_manager_get_event_group() {
return wm_event_group;
}
uint8_t wifi_manager_ap_count() {
return ap_store.count;
};
static esp_err_t wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
ESP_LOGI(TAG, "wifi event: %d", event_id);
if(event_id == WIFI_EVENT_STA_START) {
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
//ESP_ERROR_CHECK(esp_wifi_connect());
} else if(event_id == WIFI_EVENT_STA_CONNECTED) {
ESP_LOGI(TAG, "WIFI_EVENT_STA_CONNECTED");
xEventGroupSetBits(wm_event_group, WIFI_CONNECTED);
} else if(event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
ESP_LOGI(TAG, "Got IP: %s\n",
ip4addr_ntoa(&event->ip_info.ip));
xEventGroupSetBits(wm_event_group, WM_GOT_IP);
} else if(event_id == SYSTEM_EVENT_STA_DISCONNECTED) {
wifi_event_sta_disconnected_t *event = ( wifi_event_sta_disconnected_t*)event_data;
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED: reason: %d", event->reason);
xEventGroupClearBits(wm_event_group, WIFI_CONNECTED);
} else if(event_id == SYSTEM_EVENT_SCAN_DONE) {
ESP_LOGI(TAG, "SYSTEM_EVENT_SCAN_DONE");
uint8_t i = 0;
uint8_t j = 0;
uint16_t ap_count;
wifi_ap_record_t *records;
xEventGroupClearBits(wm_event_group, WIFI_SCANNING);
ESP_ERROR_CHECK(esp_wifi_scan_stop());
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));
if(ap_count > 0) {
ap_store.last = -1;
records = malloc(ap_count * sizeof(wifi_ap_record_t));
ESP_LOGI(TAG, "Found %d APs", ap_count);
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_count, (wifi_ap_record_t *)records));
for(i = 0; i < ap_count; i++) {
ESP_LOGI(TAG, "AP: %s", records[i].ssid);
}
for(i = 0; i < ap_count; i++) {
ESP_LOGI(TAG, "AP: %s", records[i].ssid);
for(j = 0; j < ap_store.count; j++)
if(strcmp(&records[i].ssid, &ap_store.aps[j]) == 0) {
ap_store.last = j;
goto found;
}
}
found:
xEventGroupClearBits(wm_event_group, WIFI_SCANNING);
xEventGroupSetBits(wm_event_group, WIFI_IDLE);
if(ap_store.last != -1) {
ESP_LOGI(TAG, "Got matching ESSID: %s", ap_store.aps[ap_store.last].ssid);
wifi_manager_connect();
} else {
ESP_LOGI(TAG, "No matching APs found");
}
} else {
ESP_LOGI(TAG, "No APs found");
}
}
return ESP_OK;
}
uint8_t wifi_manager_add_ap(char *ssid, char *password) {
strcpy(ap_store.aps[ap_store.count].ssid, (char *)ssid);
strcpy(ap_store.aps[ap_store.count].password, (char *)password);
++ap_store.count;
if(ap_store.last == -1)
ap_store.last = 0;
wifi_manager_save_config();
return ap_store.count;
};
void wifi_manager_scan() {
wifi_scan_config_t scan_config = {
.ssid = &ap_store.aps[ap_store.last].ssid,
.show_hidden = true,
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
};
ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false));
ESP_LOGI(TAG, "setting WIFI_SCANNING bit");
xEventGroupSetBits(wm_event_group, WIFI_SCANNING);
xEventGroupClearBits(wm_event_group, WIFI_IDLE);
};
void wifi_manager_connect() {
wifi_config_t wifi_config = {
.sta = {
.channel = 11,
}
};
memcpy((char *)&wifi_config.sta.ssid, ap_store.aps[ap_store.last].ssid, strlen(ap_store.aps[ap_store.last].ssid) + 1);
memcpy((char *)&wifi_config.sta.password, ap_store.aps[ap_store.last].password, strlen(ap_store.aps[ap_store.last].password) + 1);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_LOGI(TAG, "wifi_init_sta finished.");
ESP_LOGI(TAG, "connect to ap SSID:%s",
wifi_config.sta.ssid);
ESP_ERROR_CHECK(esp_wifi_connect());
};
void wifi_manager_main_loop() {
ap_store.last = 0;
vTaskDelay(3000 / portTICK_PERIOD_MS);
while(true) {
EventBits_t ev_bits = xEventGroupGetBits(wm_event_group);
if(ev_bits & AP_AVAILABLE &&
((ev_bits & (WIFI_SCANNING|WIFI_CONNECTED|WIFI_CONNECTING)) == 0)
) {
ESP_LOGI(TAG, "AP Available, starting WiFi connect");
wifi_manager_connect();
//wifi_manager_scan();
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
vTaskDelay(3000 / portTICK_PERIOD_MS);
}
}
void wifi_manager_save_config() {
ESP_LOGI(TAG, "writing %d byte config", sizeof(ap_store));
ESP_LOGI(TAG, "ap_store.magic = 0x%4X", ap_store.magic);
ESP_LOGI(TAG, "ap_store.count = %d", ap_store.count);
ESP_LOGI(TAG, "ap_store.last = %d", ap_store.last);
uint8_t i = 0;
for(; i < ap_store.count; i++) {
ESP_LOGI(TAG, "AP: %s", ap_store.aps[i].ssid);
}
if(ap_store.count > 0) {
ESP_LOGI(TAG, "setting AP_AVAILABLE");
xEventGroupSetBits(wm_event_group, AP_AVAILABLE);
}
ESP_ERROR_CHECK(nvs_set_blob(nvs, "config", &ap_store, (size_t)sizeof(ap_store)));
nvs_commit(nvs);
};
void wifi_manager_reset_store() {
ESP_LOGW(TAG, "resetting store");
memset(&ap_store, 0, sizeof(ap_store));
xEventGroupClearBits(wm_event_group, AP_AVAILABLE);
ap_store.magic = WIFI_MANAGER_MAGIC;
ap_store.last = -1;
ap_store.count = 0;
wifi_manager_save_config();
};
void wifi_manager_load_config() {
size_t store_size = 0;
esp_err_t err;
err = nvs_get_blob(nvs, "config", NULL, &store_size);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) ESP_ERROR_CHECK(err);
err = nvs_get_blob(nvs, "config", &ap_store, &store_size);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) ESP_ERROR_CHECK(err);
if(ap_store.magic != WIFI_MANAGER_MAGIC) {
ESP_LOGI(TAG, "load_config got bad magic: 0x%8X", ap_store.magic);
wifi_manager_reset_store();
return wifi_manager_save_config();
}
if(ap_store.count > 0) {
xEventGroupSetBits(wm_event_group, AP_AVAILABLE);
}
uint8_t i = 0;
ESP_LOGI(TAG, "load_config found %d APs", ap_store.count);
for(; i < ap_store.count; i++)
ESP_LOGI(TAG, "AP: %s", ap_store.aps[i].ssid);
};
EventGroupHandle_t wifi_manager_start(char *hostname) {
ESP_ERROR_CHECK(nvs_open("wm-config", NVS_READWRITE, &nvs));
wm_event_group = xEventGroupCreate();
wifi_manager_load_config();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_t *netif = esp_netif_create_default_wifi_sta();
if(hostname != NULL) {
esp_netif_set_hostname(netif, hostname);
}
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
//cfg.event_handler = wifi_event_handler;
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_start());
esp_event_handler_instance_t instance_got_ip;
esp_event_handler_instance_t instance_any_id;
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,
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
&instance_got_ip));
xTaskCreate(&wifi_manager_main_loop, "wm_main_loop", 4096, NULL, 6, NULL);
return wm_event_group;
};
int wifi_manager_bootstrap_config() {
int count = 0;
ESP_LOGI(TAG, "Bootstrapping config from IDF config");
if(strlen(CONFIG_WIFI_MANAGER_TEST_AP) > 0) {
wifi_manager_add_ap(CONFIG_WIFI_MANAGER_TEST_AP, CONFIG_WIFI_MANAGER_TEST_PWD);
count++;
}
if(strlen(CONFIG_WIFI_MANAGER_TEST_AP1) > 0) {
wifi_manager_add_ap(CONFIG_WIFI_MANAGER_TEST_AP1, CONFIG_WIFI_MANAGER_TEST_PWD1);
count++;
}
if(strlen(CONFIG_WIFI_MANAGER_TEST_AP2) > 0) {
wifi_manager_add_ap(CONFIG_WIFI_MANAGER_TEST_AP2, CONFIG_WIFI_MANAGER_TEST_PWD2);
count++;
}
return count;
}