I have recently succeeded in running the ESP32 as an access point (AP), while simultaneously running it as a station (connected to my home router), and having it receive and interpret HTTP requests.
My next step is to try and run the ESP as an AP on startup, make it receive my WiFi credentials over an HTTP request (over POST requests or something, ill decide later - got that figured out), and then change from an AP to station. I know you can change it from APSTA mode to STA mode (I tried and it works), but it always crashes if I run APSTA without configuring the STA mode.
Short version, I want to input my credentials over HTTP requests, and then turn off AP mode. Also if possible, if it loses wifi connection, turn on AP mode again.
I attached the code I used at the bottom. Thank you for your time.
Regards.
- #include <string.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "freertos/event_groups.h"
- #include "lwip/err.h"
- #include "lwip/sys.h"
- #include <esp_wifi.h>
- #include <esp_event_loop.h>
- #include <esp_log.h>
- #include <esp_system.h>
- #include <nvs_flash.h>
- #include <sys/param.h>
- #include <esp_http_server.h>
- // Function Signatures:
- void wifi_init_ap_sta();
- esp_err_t hello_get_handler(httpd_req_t *req);
- httpd_handle_t start_webserver(void);
- static esp_err_t WiFi_event_handler(void *ctx, system_event_t *event);
- void wifi_init_ap_sta();
- void app_main();
- static const char *TAG="APP";
- /* //////////////////////////////////////////////////////////////////// */
- /* An HTTP GET handler */
- /* //////////////////////////////////////////////////////////////////// */
- char username[32];
- char password[32];
- bool check = false;
- uint32_t timeNow;
- esp_err_t hello_get_handler(httpd_req_t *req)
- {
- char* buf;
- size_t buf_len;
- /*
- * Get header value (request msg Headers) string length and
- * allocate memory for length + 1, extra byte for null termination
- */
- buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1; //Host returns the IP address
- if (buf_len > 1) {
- buf = malloc(buf_len);
- /* Copy null terminated value string into buffer */
- if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
- ESP_LOGI(TAG, "Found header => Host: %s", buf);
- }
- free(buf);
- }
- /*
- * Read URL query string length and allocate memory for length + 1,
- * extra byte for null termination
- */
- buf_len = httpd_req_get_url_query_len(req) + 1;
- if (buf_len > 1) {
- buf = malloc(buf_len);
- if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
- ESP_LOGI(TAG, "Found URL query => %s", buf);
- /* Get value of expected key from query string (parameters) */
- if (httpd_query_key_value(buf, "user", username, sizeof(username)) == ESP_OK) {
- ESP_LOGI(TAG, "Found URL query parameter => Username=%s", username);
- }
- if (httpd_query_key_value(buf, "pass", password, sizeof(password)) == ESP_OK) {
- ESP_LOGI(TAG, "Found URL query parameter => Password=%s", password);
- }
- }
- }
- // Send response with custom headers and body set as the string passed in user context
- const char* resp_str = (const char*) req->user_ctx;
- httpd_resp_send(req, resp_str, strlen(resp_str)); //This is essential regardless
- /* After sending the HTTP response, the old HTTP request
- * headers are lost. Check if HTTP request headers can be read now. */
- if (httpd_req_get_hdr_value_len(req, "Host") == 0) {
- ESP_LOGI(TAG, "Request headers lost");
- }
- return ESP_OK;
- }
- httpd_uri_t hello = {
- .uri = "/hello",
- .method = HTTP_GET,
- .handler = hello_get_handler,
- // pass a response string in user context to demonstrate it's usage:
- .user_ctx = "Hello World!" //
- };
- /* //////////////////////////////////////////////////////////////////// */
- /* START WEBSERVER + REGISTER HANDLERS */
- /* //////////////////////////////////////////////////////////////////// */
- httpd_handle_t start_webserver(void)
- {
- httpd_handle_t server = NULL;
- httpd_config_t config = HTTPD_DEFAULT_CONFIG();
- // Start the httpd server
- ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
- if (httpd_start(&server, &config) == ESP_OK) {
- // Set URI handlers
- ESP_LOGI(TAG, "Registering URI handlers");
- httpd_register_uri_handler(server, &hello);
- return server;
- }
- ESP_LOGI(TAG, "Error starting server!");
- return NULL;
- }
- void stop_webserver(httpd_handle_t server)
- {
- // Stop the httpd server
- httpd_stop(server);
- }
- /* //////////////////////////////////////////////////////////////////// */
- /* EVENT HANDLER */
- /* //////////////////////////////////////////////////////////////////// */
- static esp_err_t WiFi_event_handler(void *ctx, system_event_t *event)
- {
- httpd_handle_t *server = (httpd_handle_t *) ctx;
- switch (event->event_id)
- {
- //--------------- STA events ---------------//
- case SYSTEM_EVENT_STA_START:
- ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
- ESP_ERROR_CHECK(esp_wifi_connect());
- break;
- case SYSTEM_EVENT_STA_GOT_IP:
- ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
- ESP_LOGI(TAG, "Got IP: '%s'",
- ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
- /* Start the web server */
- // if (*server == NULL)
- // {
- // *server = start_webserver();
- // }
- break;
- case SYSTEM_EVENT_STA_DISCONNECTED:
- ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED");
- ESP_ERROR_CHECK(esp_wifi_connect());
- /* Stop the web server */
- if (*server)
- {
- stop_webserver(*server);
- *server = NULL;
- }
- break;
- //--------------- AP events ---------------//
- case SYSTEM_EVENT_AP_STACONNECTED:
- ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d",
- MAC2STR(event->event_info.sta_connected.mac),
- event->event_info.sta_connected.aid);
- break;
- case SYSTEM_EVENT_AP_STADISCONNECTED:
- ESP_LOGI(TAG, "station:" MACSTR "leave, AID=%d",
- MAC2STR(event->event_info.sta_disconnected.mac),
- event->event_info.sta_disconnected.aid);
- break;
- default:
- break;
- }
- return ESP_OK;
- }
- /* //////////////////////////////////////////////////////////////////// */
- /* CONFIGURING WIFI */
- /* //////////////////////////////////////////////////////////////////// */
- #define CONFIG_AP_SSID CONFIGURE
- #define CONFIG_AP_PASS CONFIGURE
- #define CONFIG_STA_SSID CONFIGURE
- #define CONFIG_STA_PASS CONFIGURE
- #define CONFIG_MAX_CONN 4 //default is also 4
- /* FreeRTOS event group to signal when we are connected*/
- // static EventGroupHandle_t s_wifi_event_group;
- void wifi_init_ap_sta()
- {
- tcpip_adapter_init(); //initialize the TCP/IP stack (Done once at the start of the code)
- ESP_ERROR_CHECK(esp_event_loop_init(WiFi_event_handler, NULL));
- wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
- ESP_ERROR_CHECK(esp_wifi_init(&cfg));
- ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
- //Write configurations for both AP and STA modes
- wifi_config_t wifi_ap_config = {
- .ap = {
- .ssid = CONFIG_AP_SSID,
- .ssid_len = (uint8_t)strlen(CONFIG_AP_SSID),
- .password = CONFIG_AP_PASS,
- .max_connection = CONFIG_MAX_CONN,
- .authmode = WIFI_AUTH_WPA_WPA2_PSK}};
- if (strlen(CONFIG_AP_PASS) == 0) //if no password, leave it open
- {
- wifi_ap_config.ap.authmode = WIFI_AUTH_OPEN;
- }
- // --------------- Configuring STA: --------------- //
- // wifi_config_t wifi_sta_config = {
- // .sta = {
- // .ssid = CONFIG_STA_SSID,
- // .password = CONFIG_STA_PASS,
- // },
- // };
- //Set the configurations and start WiFi
- ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); //Set Wifi mode to AP
- ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_ap_config));
- // ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config));
- ESP_ERROR_CHECK(esp_wifi_start());
- ESP_LOGI(TAG, "Connecting to ap SSID:%s, password:%s", CONFIG_STA_SSID, CONFIG_STA_PASS);
- }
- /* //////////////////////////////////////////////////////////////////// */
- /* MAIN */
- /* //////////////////////////////////////////////////////////////////// */
- void app_main()
- {
- //Initialize NVS
- 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);
- wifi_init_ap_sta(); // Start WiFi with the chosen configs
- start_webserver(); // Enable HTTP requests
- }