#include #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 "esp_netif_sntp.h" #include "wifi_connect.h" #include "wifi_credentials.h" #include "audio_driver.h" #define ESP_MAXIMUM_RETRY 5 /* FreeRTOS event group to signal when we are connected */ static EventGroupHandle_t s_wifi_event_group; /* The event group allows multiple bits for each event, but we only care about two events: * - we are connected to the AP with an IP * - we failed to connect after the maximum amount of retries */ #define WIFI_CONNECTED_BIT BIT0 #define WIFI_FAIL_BIT BIT1 static const char *TAG = "wifi station"; static bool s_was_connected = false; static bool s_first_time_connect = true; static void 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) { esp_wifi_connect(); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT); xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); ESP_LOGI(TAG, "Disconnected from AP"); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); xEventGroupClearBits(s_wifi_event_group, WIFI_FAIL_BIT); xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } } static void init_sntp(void) { ESP_LOGI("SNTP", "Initializing SNTP..."); esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org"); ESP_ERROR_CHECK(esp_netif_sntp_init(&config)); } static void wifi_manager_task(void *pvParameters) { while (1) { EventBits_t bits = xEventGroupGetBits(s_wifi_event_group); if (!(bits & WIFI_CONNECTED_BIT)) { // We are not connected! if (s_was_connected) { // We lost connection! ESP_LOGW(TAG, "Wi-Fi connection lost! Playing alert..."); set_led_state(LED_STATE_WIFI_CONNECTING); Audio_Play_Music_To_End("file://spiffs/disconnected_wifi.mp3"); s_was_connected = false; } int retry_count = 0; bool success = false; while (retry_count < ESP_MAXIMUM_RETRY) { ESP_LOGI(TAG, "Attempting Wi-Fi connection (try %d/%d)...", retry_count + 1, ESP_MAXIMUM_RETRY); set_led_state(LED_STATE_WIFI_CONNECTING); xEventGroupClearBits(s_wifi_event_group, WIFI_FAIL_BIT); esp_wifi_connect(); // Wait up to 6 seconds for connection bit bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(6000)); if (bits & WIFI_CONNECTED_BIT) { success = true; break; } retry_count++; } if (success) { ESP_LOGI(TAG, "Wi-Fi Connected successfully."); s_was_connected = true; set_led_state(LED_STATE_SERVER_CONNECTING); // Play connected audio prompt Audio_Play_Music_To_End("file://spiffs/connected_wifi.mp3"); s_first_time_connect = false; } else { ESP_LOGW(TAG, "Wi-Fi connection failed. Retrying in 10 seconds..."); set_led_state(LED_STATE_WIFI_FAILED); // Play "Still not working, let me try again in a moment" Audio_Play_Music_To_End("file://spiffs/retry_later.mp3"); // Wait 10 seconds before next connection attempt vTaskDelay(pdMS_TO_TICKS(10000)); // Play "Connecting to the Wi-Fi" chime before retrying Audio_Play_Music_To_End("file://spiffs/connecting_wifi.mp3"); } } else { // Already connected! Keep monitoring vTaskDelay(pdMS_TO_TICKS(1000)); } } } bool wifi_is_connected(void) { if (s_wifi_event_group == NULL) return false; EventBits_t bits = xEventGroupGetBits(s_wifi_event_group); return (bits & WIFI_CONNECTED_BIT) != 0; } esp_err_t wifi_init_sta(void) { s_wifi_event_group = xEventGroupCreate(); ESP_ERROR_CHECK(esp_netif_init()); // Only create event loop if it hasn't been created yet esp_err_t err = esp_event_loop_create_default(); if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { ESP_ERROR_CHECK(err); } esp_netif_create_default_wifi_sta(); // Initialize SNTP exactly once during startup init_sntp(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 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, &event_handler, NULL, &instance_any_id)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip)); wifi_config_t wifi_config = { .sta = { .ssid = WIFI_SSID, .password = WIFI_PASSWORD, .threshold.authmode = WIFI_AUTH_WPA2_PSK, }, }; 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, "Starting Wi-Fi manager task..."); xTaskCreate(wifi_manager_task, "wifi_manager_task", 4096, NULL, 5, NULL); // Wait blockingly on first boot for initial connection ESP_LOGI(TAG, "Waiting for initial Wi-Fi connection..."); xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY); return ESP_OK; }