开始前适用开发板:ESP32 系列 · 开发框架:ESP-IDF
文档类型:ESP-IDF 通用 API 教程,不绑定单一开发板。
板级例程见 热门例程详解。
目录
配网简介
配网(Provisioning)是指将 WiFi 网络的 SSID 和密码等信息传输给 ESP32 设备的过程。ESP-IDF 提供了多种配网方式,每种方式都有其特点和适用场景。
配网方式比较
| 配网方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| SmartConfig | 无需额外硬件,操作简单 | 成功率受环境影响 | 简单家用设备 |
| AirKiss | 微信生态集成,用户友好 | 仅限微信平台 | 微信智能硬件 |
| SoftAP | 稳定可靠,配置灵活 | 需要切换网络 | 商用设备 |
| 蓝牙配网 | 连接稳定,交互性好 | 需要蓝牙支持 | 高端智能设备 |
| 二维码配网 | 操作简单,用户友好 | 需要显示设备 | 带屏幕设备 |
SmartConfig 配网
1. 基本实现
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_smartconfig.h"
#include "esp_netif.h"
static const char *TAG = "smartconfig";
static EventGroupHandle_t s_wifi_event_group;
static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static void smartconfig_task(void *parm);
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) {
xTaskCreate(smartconfig_task, "smartconfig_task", 4096, NULL, 3, NULL);
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
esp_wifi_connect();
xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
ESP_LOGI(TAG, "找到信道");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
ESP_LOGI(TAG, "获取到 SSID 和密码");
smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
ESP_LOGI(TAG, "SSID: %s", wifi_config.sta.ssid);
ESP_LOGI(TAG, "PASSWORD: %s", wifi_config.sta.password);
ESP_ERROR_CHECK(esp_wifi_disconnect());
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_connect());
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
}
}
static void smartconfig_task(void *parm)
{
EventBits_t uxBits;
ESP_ERROR_CHECK(esp_smartconfig_set_type(SC_TYPE_ESPTOUCH));
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_smartconfig_start(&cfg));
while (1) {
uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT,
true, false, portMAX_DELAY);
if (uxBits & CONNECTED_BIT) {
ESP_LOGI(TAG, "WiFi 已连接");
}
if (uxBits & ESPTOUCH_DONE_BIT) {
ESP_LOGI(TAG, "SmartConfig 已完成");
esp_smartconfig_stop();
vTaskDelete(NULL);
}
}
}
void app_main(void)
{
// 初始化 NVS
ESP_ERROR_CHECK(nvs_flash_init());
// 初始化 TCP/IP 适配器
ESP_ERROR_CHECK(esp_netif_init());
// 创建默认事件循环
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
// 创建 WiFi 事件组
s_wifi_event_group = xEventGroupCreate();
// 初始化 WiFi
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// 注册事件处理函数
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
// 设置 WiFi 模式并启动
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
}
SoftAP 配网
1. 基本实现
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.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"
#include "esp_http_server.h"
static const char *TAG = "softap_prov";
// 配网页面 HTML
static const char *html_page = "<!DOCTYPE html><html><head><title>WiFi 配置</title></head>"
"<body><h1>WiFi 配置</h1>"
"<form method='post' action='/configure'>"
"SSID: <input type='text' name='ssid'><br>"
"密码: <input type='password' name='password'><br>"
"<input type='submit' value='连接'>"
"</form></body></html>";
// HTTP GET 处理函数
static esp_err_t get_handler(httpd_req_t *req)
{
httpd_resp_send(req, html_page, strlen(html_page));
return ESP_OK;
}
// HTTP POST 处理函数
static esp_err_t post_handler(httpd_req_t *req)
{
char buf[100];
char ssid[32] = {0};
char password[64] = {0};
int ret, remaining = req->content_len;
while (remaining > 0) {
if ((ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)))) <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
continue;
}
return ESP_FAIL;
}
// 解析 POST 数据
char *ssid_start = strstr(buf, "ssid=");
char *pass_start = strstr(buf, "password=");
if (ssid_start && pass_start) {
ssid_start += 5; // 跳过 "ssid="
pass_start += 9; // 跳过 "password="
char *ssid_end = strchr(ssid_start, '&');
char *pass_end = strchr(pass_start, '&');
if (ssid_end) *ssid_end = 0;
if (pass_end) *pass_end = 0;
strncpy(ssid, ssid_start, sizeof(ssid) - 1);
strncpy(password, pass_start, sizeof(password) - 1);
}
remaining -= ret;
}
// 配置 WiFi
wifi_config_t wifi_config = {
.sta = {
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.capable = true,
.required = false
},
},
};
memcpy(wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, password, sizeof(wifi_config.sta.password));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_connect());
// 发送响应
const char *resp = "WiFi 配置已更新,正在连接...";
httpd_resp_send(req, resp, strlen(resp));
return ESP_OK;
}
// 启动 HTTP 服务器
static httpd_handle_t start_webserver(void)
{
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
httpd_uri_t uri_get = {
.uri = "/",
.method = HTTP_GET,
.handler = get_handler,
.user_ctx = NULL
};
httpd_uri_t uri_post = {
.uri = "/configure",
.method = HTTP_POST,
.handler = post_handler,
.user_ctx = NULL
};
if (httpd_start(&server, &config) == ESP_OK) {
httpd_register_uri_handler(server, &uri_get);
httpd_register_uri_handler(server, &uri_post);
}
return server;
}
void app_main(void)
{
// 初始化 NVS
ESP_ERROR_CHECK(nvs_flash_init());
// 初始化网络接口
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_ap();
// 初始化 WiFi
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// 配置 AP
wifi_config_t wifi_config = {
.ap = {
.ssid = "ESP32_Config",
.ssid_len = strlen("ESP32_Config"),
.channel = 1,
.password = "12345678",
.max_connection = 4,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
// 启动 Web 服务器
start_webserver();
ESP_LOGI(TAG, "SoftAP 配网服务已启动");
}
蓝牙配网
1. 基本实现
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_gatt_common_api.h"
static const char *TAG = "ble_prov";
#define PROFILE_NUM 1
#define PROFILE_APP_IDX 0
#define ESP_APP_ID 0x55
#define SAMPLE_DEVICE_NAME "ESP_PROV"
#define SVC_INST_ID 0
static uint8_t adv_config_done = 0;
#define adv_config_flag (1 << 0)
#define scan_rsp_config_flag (1 << 1)
static uint16_t wifi_handle_table[3];
static esp_ble_adv_params_t adv_params = {
.adv_int_min = 0x20,
.adv_int_max = 0x40,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
struct gatts_profile_inst {
esp_gatts_cb_t gatts_cb;
uint16_t gatts_if;
uint16_t app_id;
uint16_t conn_id;
uint16_t service_handle;
esp_gatt_srvc_id_t service_id;
uint16_t char_handle;
esp_bt_uuid_t char_uuid;
esp_gatt_perm_t perm;
esp_gatt_char_prop_t property;
uint16_t descr_handle;
esp_bt_uuid_t descr_uuid;
};
static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = {
[PROFILE_APP_IDX] = {
.gatts_cb = gatts_profile_event_handler,
.gatts_if = ESP_GATT_IF_NONE,
},
};
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
adv_config_done &= (~adv_config_flag);
if (adv_config_done == 0) {
esp_ble_gap_start_advertising(&adv_params);
}
break;
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
adv_config_done &= (~scan_rsp_config_flag);
if (adv_config_done == 0) {
esp_ble_gap_start_advertising(&adv_params);
}
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(TAG, "广播启动失败");
}
break;
default:
break;
}
}
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
esp_ble_gatts_cb_param_t *param)
{
if (event == ESP_GATTS_REG_EVT) {
if (param->reg.status == ESP_GATT_OK) {
gl_profile_tab[param->reg.app_id].gatts_if = gatts_if;
} else {
ESP_LOGE(TAG, "注册应用失败,app_id %04x, status %d",
param->reg.app_id,
param->reg.status);
return;
}
}
for (int idx = 0; idx < PROFILE_NUM; idx++) {
if (gatts_if == ESP_GATT_IF_NONE || gatts_if == gl_profile_tab[idx].gatts_if) {
if (gl_profile_tab[idx].gatts_cb) {
gl_profile_tab[idx].gatts_cb(event, gatts_if, param);
}
}
}
}
static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
switch (event) {
case ESP_GATTS_REG_EVT:
esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
esp_ble_gap_config_adv_data(&adv_data);
esp_ble_gap_config_adv_data(&scan_rsp_data);
esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_APP_IDX].service_id, 3);
break;
case ESP_GATTS_WRITE_EVT:
if (!param->write.is_prep) {
// 处理接收到的 WiFi 配置信息
char wifi_config[64] = {0};
memcpy(wifi_config, param->write.value, param->write.len);
// 解析 SSID 和密码
char *ssid = strtok(wifi_config, ",");
char *password = strtok(NULL, ",");
if (ssid && password) {
wifi_config_t wifi_cfg = {
.sta = {
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
},
};
memcpy(wifi_cfg.sta.ssid, ssid, strlen(ssid));
memcpy(wifi_cfg.sta.password, password, strlen(password));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg));
ESP_ERROR_CHECK(esp_wifi_connect());
}
esp_ble_gatts_send_response(gatts_if, param->write.conn_id,
param->write.trans_id, ESP_GATT_OK, NULL);
}
break;
default:
break;
}
}
void app_main(void)
{
// 初始化 NVS
ESP_ERROR_CHECK(nvs_flash_init());
// 初始化蓝牙
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
ESP_ERROR_CHECK(esp_bluedroid_init());
ESP_ERROR_CHECK(esp_bluedroid_enable());
ESP_ERROR_CHECK(esp_ble_gatts_register_callback(gatts_event_handler));
ESP_ERROR_CHECK(esp_ble_gap_register_callback(gap_event_handler));
ESP_ERROR_CHECK(esp_ble_gatts_app_register(ESP_APP_ID));
// 初始化 WiFi
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_LOGI(TAG, "蓝牙配网服务已启动");
}
二维码配网
1. 基本实现
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_camera.h"
#include "quirc.h"
static const char *TAG = "qr_prov";
// 二维码扫描任务
static void qr_scan_task(void *arg)
{
struct quirc *qr;
uint8_t *image;
struct quirc_code code;
struct quirc_data data;
camera_fb_t *fb = NULL;
// 初始化二维码解码器
qr = quirc_new();
if (!qr) {
ESP_LOGE(TAG, "无法创建二维码解码器");
vTaskDelete(NULL);
return;
}
while (1) {
// 获取摄像头图像
fb = esp_camera_fb_get();
if (!fb) {
ESP_LOGE(TAG, "获取摄像头图像失败");
continue;
}
// 设置图像缓冲区
if (quirc_resize(qr, fb->width, fb->height) < 0) {
ESP_LOGE(TAG, "调整二维码解码器大小失败");
esp_camera_fb_return(fb);
continue;
}
image = quirc_begin(qr, NULL, NULL);
memcpy(image, fb->buf, fb->len);
// 识别二维码
quirc_end(qr);
int count = quirc_count(qr);
if (count > 0) {
// 提取二维码数据
quirc_extract(qr, 0, &code);
if (quirc_decode(&code, &data) == 0) {
ESP_LOGI(TAG, "二维码内容: %s", data.payload);
// 解析 WiFi 配置信息
char *wifi_info = (char *)data.payload;
char *ssid = strtok(wifi_info, ",");
char *password = strtok(NULL, ",");
if (ssid && password) {
wifi_config_t wifi_config = {
.sta = {
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.capable = true,
.required = false
},
},
};
memcpy(wifi_config.sta.ssid, ssid, strlen(ssid));
memcpy(wifi_config.sta.password, password, strlen(password));
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_connect());
ESP_LOGI(TAG, "WiFi 配置已更新,正在连接...");
}
}
}
esp_camera_fb_return(fb);
vTaskDelay(pdMS_TO_TICKS(1000));
}
quirc_destroy(qr);
vTaskDelete(NULL);
}
void app_main(void)
{
// 初始化 NVS
ESP_ERROR_CHECK(nvs_flash_init());
// 初始化摄像头
camera_config_t camera_config = {
.pin_pwdn = CONFIG_CAMERA_PIN_PWDN,
.pin_reset = CONFIG_CAMERA_PIN_RESET,
.pin_xclk = CONFIG_CAMERA_PIN_XCLK,
.pin_sscb_sda = CONFIG_CAMERA_PIN_SIOD,
.pin_sscb_scl = CONFIG_CAMERA_PIN_SIOC,
.pin_d7 = CONFIG_CAMERA_PIN_D7,
.pin_d6 = CONFIG_CAMERA_PIN_D6,
.pin_d5 = CONFIG_CAMERA_PIN_D5,
.pin_d4 = CONFIG_CAMERA_PIN_D4,
.pin_d3 = CONFIG_CAMERA_PIN_D3,
.pin_d2 = CONFIG_CAMERA_PIN_D2,
.pin_d1 = CONFIG_CAMERA_PIN_D1,
.pin_d0 = CONFIG_CAMERA_PIN_D0,
.pin_vsync = CONFIG_CAMERA_PIN_VSYNC,
.pin_href = CONFIG_CAMERA_PIN_HREF,
.pin_pclk = CONFIG_CAMERA_PIN_PCLK,
.xclk_freq_hz = CONFIG_XCLK_FREQ,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_GRAYSCALE,
.frame_size = FRAMESIZE_QVGA,
.jpeg_quality = 12,
.fb_count = 1,
};
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK) {
ESP_LOGE(TAG, "摄像头初始化失败");
return;
}
// 初始化 WiFi
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));
// 创建二维码扫描任务
xTaskCreate(qr_scan_task, "qr_scan_task", 8192, NULL, 5, NULL);
ESP_LOGI(TAG, "二维码配网服务已启动");
}
常见问题
1. 配网失败
常见原因和解决方法:
-
网络环境问题:
- 确保 WiFi 信号强度足够
- 检查路由器是否支持相应的认证方式
- 避免在干扰源附近配网
-
参数设置问题:
- 检查 SSID 和密码是否正确
- 确认认证模式设置正确
- 验证配网数据格式
-
硬件问题:
- 检查天线连接
- 确保供电稳定
- 验证外设(如摄像头)工作正常
-
硬件问题:
- 检查摄像头连接(二维码配网)
- 确保蓝牙模块正常(蓝牙配网)
- 验证天线连接正常
2. 配网超时
常见原因和解决方法:
-
网络拥塞:
- 选择合适的配网时间
- 增加重试次数
- 延长超时时间
-
设备响应慢:
- 优化配网流程
- 减少不必要的操作
- 考虑使用更稳定的配网方式
3. 安全问题
配网过程中的安全注意事项:
-
数据加密:
- 使用 HTTPS/SSL 传输
- 加密敏感信息
- 使用安全的认证方式
-
访问控制:
- 限制配网时间
- 设置访问密码
- 使用一次性配网码
性能优化
1. 提高配网成功率
// 配网重试机制
void wifi_provision_retry(void)
{
int retry_count = 0;
const int max_retries = 3;
while (retry_count < max_retries) {
if (start_provisioning() == ESP_OK) {
ESP_LOGI(TAG, "配网成功");
break;
}
retry_count++;
ESP_LOGW(TAG, "配网失败,正在重试 (%d/%d)", retry_count, max_retries);
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
// 配网超时处理
void wifi_provision_with_timeout(void)
{
const int timeout_seconds = 300; // 5分钟超时
TickType_t start_time = xTaskGetTickCount();
while ((xTaskGetTickCount() - start_time) < pdMS_TO_TICKS(timeout_seconds * 1000)) {
if (check_provision_status() == PROVISION_DONE) {
ESP_LOGI(TAG, "配网成功");
return;
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
ESP_LOGW(TAG, "配网超时");
// 执行超时处理逻辑
}
2. 优化内存使用
// 优化内存分配
void optimize_memory_usage(void)
{
// 使用静态缓冲区
static uint8_t provision_buffer[1024];
// 避免频繁的内存分配/释放
while (1) {
process_provision_data(provision_buffer, sizeof(provision_buffer));
vTaskDelay(pdMS_TO_TICKS(100));
}
}
// 分块处理大数据
void handle_large_data(const uint8_t *data, size_t len)
{
const size_t chunk_size = 256;
size_t processed = 0;
while (processed < len) {
size_t current_chunk = MIN(chunk_size, len - processed);
process_data_chunk(data + processed, current_chunk);
processed += current_chunk;
}
}
3. 降低功耗
// 低功耗配网模式
void low_power_provisioning(void)
{
// 配网前降低 CPU 频率
esp_pm_config_esp32_t pm_config = {
.max_freq_mhz = 80,
.min_freq_mhz = 40,
.light_sleep_enable = true
};
esp_pm_configure(&pm_config);
// 配网完成后恢复正常频率
pm_config.max_freq_mhz = 240;
esp_pm_configure(&pm_config);
}
// 动态调整发射功率
void adjust_tx_power(void)
{
// 根据信号强度调整发射功率
wifi_power_t power_level;
int8_t rssi = get_current_rssi();
if (rssi > -50) {
power_level = WIFI_POWER_7dBm;
} else if (rssi > -65) {
power_level = WIFI_POWER_11dBm;
} else {
power_level = WIFI_POWER_19_5dBm;
}
esp_wifi_set_max_tx_power(power_level);
}
总结
本教程详细介绍了 ESP-IDF 中的各种配网方式,包括:
-
SmartConfig 配网:
- 简单易用,适合家用设备
- 无需额外硬件
- 受环境影响较大
-
SoftAP 配网:
- 稳定可靠
- 配置灵活
- 需要切换网络
-
蓝牙配网:
- 连接稳定
- 交互性好
- 需要蓝牙支持
-
二维码配网:
- 操作简单
- 用户友好
- 需要摄像头支持
每种配网方式都有其优缺点和适用场景,开发者可以根据具体需求选择合适的配网方式。同时,通过实现合适的重试机制、超时处理和安全措施,可以提高配网的成功率和可靠性。