From 846f65cfa7b709072982e12a6522f225d989a8fb Mon Sep 17 00:00:00 2001 From: Andrey Aleksandrov Date: Tue, 30 Dec 2025 21:48:53 +0200 Subject: [PATCH] Initial commit --- CHANGELOG.md | 12 ++ library.json | 16 +++ wifi_manager.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++++ wifi_manager.h | 101 ++++++++++++++++ 4 files changed, 441 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 library.json create mode 100644 wifi_manager.c create mode 100644 wifi_manager.h diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8625ef8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [v1.0.0] - 2024-12-30 + +### Added + +- Repository diff --git a/library.json b/library.json new file mode 100644 index 0000000..969fbf2 --- /dev/null +++ b/library.json @@ -0,0 +1,16 @@ +{ + "name": "wifi_manager", + "version": "1.0.0", + "description": "WiFi connection management library with auto-reconnection for ESP32", + "keywords": "wifi, esp32, connection, reconnect, event, callback", + "authors": { + "name": "ESP32C6-DHT22 Project" + }, + "license": "MIT", + "frameworks": [ + "espidf" + ], + "platforms": [ + "espressif32" + ] +} \ No newline at end of file diff --git a/wifi_manager.c b/wifi_manager.c new file mode 100644 index 0000000..f6af856 --- /dev/null +++ b/wifi_manager.c @@ -0,0 +1,312 @@ +#include "wifi_manager.h" +#include "esp_log.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include + +static const char *TAG = "WIFI_MANAGER"; + +// WiFi manager state +static bool is_initialized = false; +static wifi_status_t current_status = WIFI_STATUS_DISCONNECTED; +static EventGroupHandle_t wifi_event_group = NULL; +static wifi_event_callback_t user_callback = NULL; +static char stored_ip[16] = {0}; + +// Event group bits +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +// Event handler instances +static esp_event_handler_instance_t instance_any_id; +static esp_event_handler_instance_t instance_got_ip; + +// WiFi event handler +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) + { + ESP_LOGI(TAG, "WiFi started, connecting..."); + current_status = WIFI_STATUS_CONNECTING; + esp_wifi_connect(); + if (user_callback) + { + user_callback(current_status, NULL); + } + } + else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI(TAG, "WiFi disconnected, trying to reconnect..."); + current_status = WIFI_STATUS_DISCONNECTED; + memset(stored_ip, 0, sizeof(stored_ip)); + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT); + if (user_callback) + { + user_callback(current_status, NULL); + } + } + 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; + snprintf(stored_ip, sizeof(stored_ip), IPSTR, IP2STR(&event->ip_info.ip)); + ESP_LOGI(TAG, "WiFi connected! IP: %s", stored_ip); + current_status = WIFI_STATUS_CONNECTED; + xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT); + if (user_callback) + { + user_callback(current_status, stored_ip); + } + } +} + +esp_err_t wifi_manager_init(const char *ssid, const char *password, wifi_event_callback_t event_callback) +{ + if (is_initialized) + { + ESP_LOGW(TAG, "WiFi manager already initialized"); + return ESP_OK; + } + + if (ssid == NULL || password == NULL) + { + ESP_LOGE(TAG, "SSID and password cannot be NULL"); + return ESP_ERR_INVALID_ARG; + } + + ESP_LOGI(TAG, "Initializing WiFi manager"); + + user_callback = event_callback; + current_status = WIFI_STATUS_DISCONNECTED; + + // Create event group + wifi_event_group = xEventGroupCreate(); + if (wifi_event_group == NULL) + { + ESP_LOGE(TAG, "Failed to create WiFi event group"); + return ESP_ERR_NO_MEM; + } + + // Initialize netif + ESP_ERROR_CHECK(esp_netif_init()); + + // Create default event loop if not exists + esp_err_t ret = esp_event_loop_create_default(); + if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) + { + ESP_LOGE(TAG, "Failed to create event loop: %s", esp_err_to_name(ret)); + vEventGroupDelete(wifi_event_group); + wifi_event_group = NULL; + return ret; + } + + // Create default WiFi STA + esp_netif_create_default_wifi_sta(); + + // Initialize WiFi + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ret = esp_wifi_init(&cfg); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Failed to initialize WiFi: %s", esp_err_to_name(ret)); + vEventGroupDelete(wifi_event_group); + wifi_event_group = NULL; + return ret; + } + + // Register event handlers + ret = esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, + &wifi_event_handler, + NULL, + &instance_any_id); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Failed to register WiFi event handler: %s", esp_err_to_name(ret)); + esp_wifi_deinit(); + vEventGroupDelete(wifi_event_group); + wifi_event_group = NULL; + return ret; + } + + ret = esp_event_handler_instance_register(IP_EVENT, + IP_EVENT_STA_GOT_IP, + &wifi_event_handler, + NULL, + &instance_got_ip); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Failed to register IP event handler: %s", esp_err_to_name(ret)); + esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id); + esp_wifi_deinit(); + vEventGroupDelete(wifi_event_group); + wifi_event_group = NULL; + return ret; + } + + // Configure WiFi + wifi_config_t wifi_config = { + .sta = { + .threshold.authmode = WIFI_AUTH_WPA2_PSK, + }, + }; + + strncpy((char *)wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid) - 1); + strncpy((char *)wifi_config.sta.password, password, sizeof(wifi_config.sta.password) - 1); + + ret = esp_wifi_set_mode(WIFI_MODE_STA); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Failed to set WiFi mode: %s", esp_err_to_name(ret)); + wifi_manager_deinit(); + return ret; + } + + ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_config); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Failed to set WiFi config: %s", esp_err_to_name(ret)); + wifi_manager_deinit(); + return ret; + } + + is_initialized = true; + ESP_LOGI(TAG, "WiFi manager initialized successfully"); + return ESP_OK; +} + +esp_err_t wifi_manager_start(void) +{ + if (!is_initialized) + { + ESP_LOGE(TAG, "WiFi manager not initialized"); + return ESP_ERR_INVALID_STATE; + } + + ESP_LOGI(TAG, "Starting WiFi"); + esp_err_t ret = esp_wifi_start(); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Failed to start WiFi: %s", esp_err_to_name(ret)); + current_status = WIFI_STATUS_ERROR; + return ret; + } + + return ESP_OK; +} + +esp_err_t wifi_manager_stop(void) +{ + if (!is_initialized) + { + ESP_LOGE(TAG, "WiFi manager not initialized"); + return ESP_ERR_INVALID_STATE; + } + + ESP_LOGI(TAG, "Stopping WiFi"); + current_status = WIFI_STATUS_DISCONNECTED; + memset(stored_ip, 0, sizeof(stored_ip)); + + esp_err_t ret = esp_wifi_stop(); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Failed to stop WiFi: %s", esp_err_to_name(ret)); + return ret; + } + + return ESP_OK; +} + +wifi_status_t wifi_manager_get_status(void) +{ + return current_status; +} + +bool wifi_manager_wait_for_connection(uint32_t timeout_ms) +{ + if (!is_initialized || wifi_event_group == NULL) + { + ESP_LOGE(TAG, "WiFi manager not initialized"); + return false; + } + + TickType_t timeout_ticks = (timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); + + EventBits_t bits = xEventGroupWaitBits(wifi_event_group, + WIFI_CONNECTED_BIT, + pdFALSE, + pdFALSE, + timeout_ticks); + + return (bits & WIFI_CONNECTED_BIT) != 0; +} + +esp_err_t wifi_manager_get_ip_address(char *ip_str, size_t buffer_size) +{ + if (ip_str == NULL || buffer_size < 16) + { + ESP_LOGE(TAG, "Invalid parameters for IP address"); + return ESP_ERR_INVALID_ARG; + } + + if (current_status != WIFI_STATUS_CONNECTED || strlen(stored_ip) == 0) + { + ESP_LOGW(TAG, "WiFi not connected or no IP address available"); + return ESP_ERR_INVALID_STATE; + } + + strncpy(ip_str, stored_ip, buffer_size - 1); + ip_str[buffer_size - 1] = '\0'; + + return ESP_OK; +} + +bool wifi_manager_is_connected(void) +{ + return current_status == WIFI_STATUS_CONNECTED; +} + +esp_err_t wifi_manager_deinit(void) +{ + if (!is_initialized) + { + ESP_LOGW(TAG, "WiFi manager not initialized"); + return ESP_OK; + } + + ESP_LOGI(TAG, "Deinitializing WiFi manager"); + + // Stop WiFi if running + esp_wifi_stop(); + + // Unregister event handlers + if (instance_any_id != NULL) + { + esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id); + instance_any_id = NULL; + } + + if (instance_got_ip != NULL) + { + esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip); + instance_got_ip = NULL; + } + + // Deinitialize WiFi + esp_wifi_deinit(); + + // Delete event group + if (wifi_event_group != NULL) + { + vEventGroupDelete(wifi_event_group); + wifi_event_group = NULL; + } + + current_status = WIFI_STATUS_DISCONNECTED; + memset(stored_ip, 0, sizeof(stored_ip)); + user_callback = NULL; + is_initialized = false; + + ESP_LOGI(TAG, "WiFi manager deinitialized"); + return ESP_OK; +} \ No newline at end of file diff --git a/wifi_manager.h b/wifi_manager.h new file mode 100644 index 0000000..bc91739 --- /dev/null +++ b/wifi_manager.h @@ -0,0 +1,101 @@ +#ifndef WIFI_MANAGER_H +#define WIFI_MANAGER_H + +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + /** + * @brief WiFi connection status + */ + typedef enum + { + WIFI_STATUS_DISCONNECTED = 0, + WIFI_STATUS_CONNECTING, + WIFI_STATUS_CONNECTED, + WIFI_STATUS_ERROR + } wifi_status_t; + + /** + * @brief WiFi event callback function type + * + * @param status Current WiFi status + * @param ip_address IP address string (only valid when status is CONNECTED) + */ + typedef void (*wifi_event_callback_t)(wifi_status_t status, const char *ip_address); + + /** + * @brief Initialize WiFi manager + * + * @param ssid WiFi network name + * @param password WiFi password + * @param event_callback Optional callback function for WiFi events + * @return esp_err_t ESP_OK on success, error code on failure + */ + esp_err_t wifi_manager_init(const char *ssid, const char *password, wifi_event_callback_t event_callback); + + /** + * @brief Start WiFi connection + * + * @return esp_err_t ESP_OK on success, error code on failure + */ + esp_err_t wifi_manager_start(void); + + /** + * @brief Stop WiFi connection + * + * @return esp_err_t ESP_OK on success, error code on failure + */ + esp_err_t wifi_manager_stop(void); + + /** + * @brief Get current WiFi connection status + * + * @return wifi_status_t Current WiFi status + */ + wifi_status_t wifi_manager_get_status(void); + + /** + * @brief Wait for WiFi connection with timeout + * + * @param timeout_ms Timeout in milliseconds (0 for indefinite wait) + * @return true if connected, false if timeout + */ + bool wifi_manager_wait_for_connection(uint32_t timeout_ms); + + /** + * @brief Get current IP address + * + * @param ip_str Buffer to store IP address string (minimum 16 chars) + * @param buffer_size Size of the buffer + * @return esp_err_t ESP_OK on success, error code on failure + */ + esp_err_t wifi_manager_get_ip_address(char *ip_str, size_t buffer_size); + + /** + * @brief Deinitialize WiFi manager + * + * @return esp_err_t ESP_OK on success, error code on failure + */ + esp_err_t wifi_manager_deinit(void); + + /** + * @brief Check if WiFi is connected + * + * @return true if connected, false otherwise + */ + bool wifi_manager_is_connected(void); + +#ifdef __cplusplus +} +#endif + +#endif // WIFI_MANAGER_H \ No newline at end of file