AI-WB2 配网【上】

引言
早期的Wi-Fi设备大多都用于带屏幕和输入设备的(如嵌入式设备/笔记本/手机等),配网只需要用户连接路由器的SSID输入password即可。
但是随着物联网的兴起,Wi-Fi被大量应用于没有人机交互方式的设备中,如智能插座等物联网终端产品中,而Wi-Fi(IEEE802.11)标准在设计之初是没有考虑这种无人机交互方式的配网的,也就是没有官方标准。这也就导致了市面上配网的方法多种多样,且各家玩各家的,鱼龙混杂,互不相通,整体体验偏低。
简化示意图如下:

常见的配网方式有:
- STA+AP配网
- STA配网
- 蓝牙配网
- 一键配网(SMART CONFIG)
- 其他
两个基本概念:
STA : STA称为“客户端模式”,是指设备(如手机、笔记本、单片机等)作为 Wi-Fi 客户端,连接到无线 AP(路由器或热点)以访问网络。STA 模式的特点:
- 设备需要连接到 AP 才能访问互联网或局域网。
- 典型应用:手机连接 Wi-Fi、电脑连接无线路由器等。


AP : AP 模式也称为“热点模式”或“SoftAP(软件AP)模式”,用于创建一个无线网络,允许其他 STA 设备连接。
AP 模式的特点:
- 设备自身变成 Wi-Fi 热点,其他设备可以连接到它。
- 适用于 IoT 设备配网、临时网络等应用。
STA & STA+AP配网



- 设备端(WB2/M61/ESP8266等)进入softAP模式,然后建立一个约定好的AP热点。
- 手机APP端/电脑 用户去连接步骤1中建立的热点。
- 连接后,手机与设备端建立局域网通信。
- 手机APP/电脑 通过UDP/TCP(常见的有静态网页)将配网信息(常见的是路由器)传递给设备。
- 设备端拿到配网信息之后切换为STA模式,用STA模式连接。

示例代码
#define ROUTER_SSID "your ssid" // 定义WiFi SSID
#define ROUTER_PWD "your password" // 定义WiFi密码
// WiFi 配置结构体,指定国家代码
static wifi_conf_t conf =
{
.country_code = "CN",
};
// WiFi 连接函数,连接到指定的SSID和密码
static void wifi_sta_connect(char* ssid, char* password)
{
wifi_interface_t wifi_interface;
wifi_interface = wifi_mgmr_sta_enable(); // 启用 WiFi STA 模式
wifi_mgmr_sta_connect(wifi_interface, ssid, password, NULL, NULL, 0, 0); // 连接WiFi
}
// WiFi 事件回调函数,处理各种WiFi事件
static void event_cb_wifi_event(input_event_t* event, void* private_data)
{
static char* ssid;
static char* password;
switch (event->code)
{
case CODE_WIFI_ON_INIT_DONE: // WiFi初始化完成
{
blog_info("[APP] [EVT] INIT DONE %lld", aos_now_ms());
wifi_mgmr_start_background(&conf); // 启动 WiFi 管理器
}
break;
case CODE_WIFI_ON_MGMR_DONE: // WiFi管理器初始化完成
{
blog_info("[APP] [EVT] MGMR DONE %lld", aos_now_ms());
wifi_sta_connect(ROUTER_SSID, ROUTER_PWD); // 连接WiFi
}
break;
case CODE_WIFI_ON_SCAN_DONE: // WiFi扫描完成
{
blog_info("[APP] [EVT] SCAN Done %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_DISCONNECT: // WiFi断开连接
{
blog_info("[APP] [EVT] disconnect %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_CONNECTING: // WiFi正在连接
{
blog_info("[APP] [EVT] Connecting %lld", aos_now_ms());
}
break;
case CODE_WIFI_CMD_RECONNECT: // WiFi重连命令
{
blog_info("[APP] [EVT] Reconnect %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_CONNECTED: // WiFi已连接
{
blog_info("[APP] [EVT] connected %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_PRE_GOT_IP: // WiFi连接成功,准备获取IP
{
blog_info("[APP] [EVT] connected %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_GOT_IP: // WiFi成功获取IP地址
{
blog_info("[APP] [EVT] GOT IP %lld", aos_now_ms());
blog_info("[SYS] Memory left is %d Bytes", xPortGetFreeHeapSize()); // 记录剩余内存
//获取到ip地址之后就可以开别的任务。
}
break;
case CODE_WIFI_ON_PROV_SSID: // 接收到配网的SSID
{
blog_info("[APP] [EVT] [PROV] [SSID] %lld: %s", aos_now_ms(), event->value ? (const char*)event->value : "UNKNOWN");
if (ssid)
{
vPortFree(ssid);
ssid = NULL;
}
ssid = (char*)event->value;
}
break;
case CODE_WIFI_ON_PROV_BSSID: // 接收到配网的BSSID
{
blog_info("[APP] [EVT] [PROV] [BSSID] %lld: %s", aos_now_ms(), event->value ? (const char*)event->value : "UNKNOWN");
if (event->value)
{
vPortFree((void*)event->value);
}
}
break;
case CODE_WIFI_ON_PROV_PASSWD: // 接收到配网的密码
{
blog_info("[APP] [EVT] [PROV] [PASSWD] %lld: %s", aos_now_ms(), event->value ? (const char*)event->value : "UNKNOWN");
if (password)
{
vPortFree(password);
password = NULL;
}
password = (char*)event->value;
}
break;
case CODE_WIFI_ON_PROV_CONNECT: // 触发配网连接
{
blog_info("[APP] [EVT] [PROV] [CONNECT] %lld", aos_now_ms());
blog_info("connecting to %s:%s...", ssid, password);
wifi_sta_connect(ssid, password);
}
break;
case CODE_WIFI_ON_PROV_DISCONNECT: // 配网断开
{
blog_info("[APP] [EVT] [PROV] [DISCONNECT] %lld", aos_now_ms());
}
break;
default: // 处理未知WiFi事件
{
blog_info("[APP] [EVT] Unknown code %u, %lld", event->code, aos_now_ms());
}
}
}
// WiFi 主任务入口
static void proc_main_entry(void* pvParameters)
{
aos_register_event_filter(EV_WIFI, event_cb_wifi_event, NULL); // 注册WiFi事件回调函数
hal_wifi_start_firmware_task(); // 启动WiFi固件任务
aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0); // 发送WiFi初始化完成事件
vTaskDelete(NULL); // 删除当前任务
}
设置静态ip
// 定义WiFi站点的SSID
#define STA_SSID "123"
// 定义WiFi站点的密码
#define STA_PASSWORD "12345678"
// 定义WiFi站点的最大连接数
#define STA_MAX_CONN_cCOUNT 15
// 定义WiFi站点的静态IP地址
#define STA_STATIC_IP "192.168.43.133"
// 定义一个宏,用于将四个字节的IP地址转换为32位无符号整数
#define IP_SET_ADDR(a, b, c, d) (((uint32_t)((a)&0xff)) | \
((uint32_t)((b)&0xff) << 8) | \
((uint32_t)((c)&0xff) << 16) | \
((uint32_t)((d)&0xff) << 24))
// 定义静态WiFi配置结构体,初始化国家代码为"CN"(中国)
static wifi_conf_t conf = {
.country_code = "CN",
};
// 定义国家代码类型变量,初始化为中国
country_code_type country_code = WIFI_COUNTRY_CODE_CN;
// 定义WiFi IP参数结构体并初始化为0
wifi_ip_params_t sta_ip_params = { 0 };
// 定义全局WiFi站点接口指针,初始化为空
static wifi_interface_t g_wifi_sta_interface = NULL;
// 定义全局WiFi站点连接状态标志,0表示未连接
static int g_wifi_sta_is_connected = 0;
// WiFi后台初始化函数,参数为国家代码
void wifi_background_init(country_code_type country_code)
{
// 定义国家代码字符串数组
char* country_code_string[WIFI_COUNTRY_CODE_MAX] = { "CN", "JP", "US", "EU" };
/* 初始化WiFi后台 */
// 将传入的国家代码复制到配置结构体中
strcpy(conf.country_code, country_code_string[country_code]);
// 启动WiFi后台管理
wifi_mgmr_start_background(&conf);
/* 启用扫描隐藏SSID功能 */
wifi_mgmr_scan_filter_hidden_ssid(0);
}
// 获取站点IP信息的函数
static int wifi_get_station_ip_str(void)
{
int state = WIFI_STATE_IDLE; // WiFi状态变量,初始化为空闲状态
ip4_addr_t ipaddr, gwaddr, maskaddr; // 定义IP地址、网关和子网掩码变量
wifi_mgmr_state_get(&state); // 获取当前WiFi状态
// 如果状态为已连接并获取IP
if (state == WIFI_STATE_CONNECTED_IP_GOT || state == WIFI_STATE_WITH_AP_CONNECTED_IP_GOT || state == CODE_WIFI_ON_GOT_IP)
{
// 获取站点IP参数
wifi_mgmr_sta_ip_get(&sta_ip_params.ip, &sta_ip_params.gateway, &sta_ip_params.netmask);
ipaddr.addr = sta_ip_params.ip; // 设置IP地址
gwaddr.addr = sta_ip_params.gateway; // 设置网关地址
maskaddr.addr = sta_ip_params.netmask; // 设置子网掩码
}
else
{
// 如果未连接,IP参数置0
ipaddr.addr = 0;
gwaddr.addr = 0;
maskaddr.addr = 0;
}
// 打印IP地址信息
blog_info("GOT %s:\"%s\"", "ip", ip4addr_ntoa(&ipaddr));
blog_info("GOT %s:\"%s\"", "gateway", ip4addr_ntoa(&gwaddr));
blog_info("GOT %s:\"%s\"", "netmask", ip4addr_ntoa(&maskaddr));
return 0;
}
// WiFi站点连接函数,参数为静态IP地址字符串
int wifi_sta_connect(const char* sta_ip)
{
struct ap_connect_adv ext_param = { 0 }; // 定义高级连接参数结构体并初始化
g_wifi_sta_interface = wifi_mgmr_sta_enable(); // 启用WiFi站点模式并获取接口
uint32_t flags = 0; // 定义标志变量
uint8_t ip[4] = { 0 }, j = 0; // 定义IP地址字节数组和计数器
char* temp_arg = (char*)malloc(6); // 分配临时字符串缓冲区
// 清空IP数组和参数结构体
memset(ip, 0, sizeof(ip));
memset(&sta_ip_params, 0, sizeof(sta_ip_params));
memset(temp_arg, 0, sizeof(temp_arg));
// 解析静态IP地址字符串到字节数组
for (int i = 0; i < 4; i++)
{
temp_arg = sta_ip;
while (*(sta_ip++) != '.')
{
j++;
}
temp_arg[j] = '\0';
ip[i] = atoi(temp_arg);
j = 0;
}
// 设置IP参数
sta_ip_params.ip = IP_SET_ADDR(ip[0], ip[1], ip[2], ip[3]); // 设置IP地址
sta_ip_params.gateway = IP_SET_ADDR(ip[0], ip[1], ip[2], 1); // 设置网关地址
sta_ip_params.netmask = IP_SET_ADDR(255, 255, 255, 0); // 设置子网掩码
ext_param.psk = NULL; // 设置PSK为空
ext_param.ap_info.type = AP_INFO_TYPE_PRESIST; // 设置AP信息类型为持久
ext_param.ap_info.time_to_live = 5; // 设置存活时间
ext_param.ap_info.band = 0; // 设置频段
flags |= WIFI_CONNECT_PMF_CAPABLE; // 设置支持PMF标志
ext_param.flags = flags; // 应用标志
// 如果已经连接
if (g_wifi_sta_is_connected == 1)
{
blog_info("sta has connect"); // 打印已连接信息
return 0;
}
else
{
wifi_mgmr_sta_autoconnect_enable(); // 启用自动连接
// 设置站点IP参数
wifi_mgmr_sta_ip_set(sta_ip_params.ip, sta_ip_params.netmask, sta_ip_params.gateway, sta_ip_params.gateway, 0);
blog_info("connect to wifi %s", STA_SSID); // 打印连接信息
// 执行站点连接
return wifi_mgmr_sta_connect_ext(g_wifi_sta_interface, STA_SSID, STA_PASSWORD, &ext_param);
}
free(temp_arg); // 释放临时缓冲区
}
// WiFi事件回调函数
static void wifi_event_cb(input_event_t* event, void* private_data)
{
static char* ssid; // 静态SSID变量
static char* password; // 静态密码变量
blog_info("[APP] [EVT] event->code %d", event->code); // 打印事件代码
blog_info("[SYS] Memory left is %d Bytes", xPortGetFreeHeapSize()); // 打印剩余内存
// 根据事件代码处理不同情况
switch (event->code)
{
case CODE_WIFI_ON_AP_STARTED: // AP启动事件
{
blog_info("[APP] [EVT] AP INIT DONE %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_AP_STOPPED: // AP停止事件
{
blog_info("[APP] [EVT] AP STOP DONE %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_INIT_DONE: // 初始化完成事件
{
blog_info("[APP] [EVT] INIT DONE %lld", aos_now_ms());
wifi_mgmr_start_background(&conf); // 启动WiFi后台
wifi_sta_connect(STA_STATIC_IP); // 连接WiFi站点
}
break;
case CODE_WIFI_ON_MGMR_DONE: // 管理器完成事件
{
blog_info("[APP] [EVT] MGMR DONE %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_SCAN_DONE: // 扫描完成事件
{
blog_info("[APP] [EVT] SCAN Done %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_DISCONNECT: // 断开连接事件
{
g_wifi_sta_is_connected = 0; // 设置未连接状态
blog_info("wifi sta disconnected"); // 打印断开信息
blog_info("[APP] [EVT] disconnect %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_CONNECTING: // 正在连接事件
{
blog_info("[APP] [EVT] Connecting %lld", aos_now_ms());
}
break;
case CODE_WIFI_CMD_RECONNECT: // 重连事件
{
blog_info("[APP] [EVT] Reconnect %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_CONNECTED: // 连接成功事件
{
blog_info("wifi sta connected"); // 打印连接成功信息
blog_info("[APP] [EVT] connected %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_PRE_GOT_IP: // 获取IP前事件
{
blog_info("[APP] [EVT] connected %lld", aos_now_ms());
}
break;
case CODE_WIFI_ON_GOT_IP: // 获取IP事件
{
blog_info("WIFI STA GOT IP"); // 打印获取IP信息
blog_info("[APP] [EVT] GOT IP %lld", aos_now_ms());
g_wifi_sta_is_connected = 1; // 设置已连接状态
wifi_get_station_ip_str(); // 获取并打印IP信息
}
break;
case CODE_WIFI_ON_PROV_SSID: // 提供SSID事件
{
blog_info("[APP] [EVT] [PROV] [SSID] %lld: %s",
aos_now_ms(),
event->value ? (const char*)event->value : "UNKNOWN");
if (ssid)
{
vPortFree(ssid); // 释放旧的SSID
ssid = NULL;
}
ssid = (char*)event->value; // 设置新的SSID
}
break;
case CODE_WIFI_ON_PROV_PASSWD: // 提供密码事件
{
blog_info("[APP] [EVT] [PROV] [PASSWD] %lld: %s", aos_now_ms(),
event->value ? (const char*)event->value : "UNKNOWN");
if (password)
{
vPortFree(password); // 释放旧的密码
password = NULL;
}
password = (char*)event->value; // 设置新的密码
}
break;
case CODE_WIFI_ON_PROV_CONNECT: // 提供连接事件
{
blog_info("connecting to %s:%s...", ssid, password); // 打印连接信息
}
break;
case CODE_WIFI_ON_PROV_DISCONNECT: // 提供断开事件
{
blog_info("[APP] [EVT] [PROV] [DISCONNECT] %lld", aos_now_ms());
}
break;
default: // 未知事件
{
blog_info("[APP] [EVT] Unknown code %u, %lld", event->code, aos_now_ms());
/* 无操作 */
}
}
}
// WiFi执行函数
void wifi_execute(void* pvParameters)
{
// 注册WiFi事件过滤器
aos_register_event_filter(EV_WIFI, wifi_event_cb, NULL);
static uint8_t stack_wifi_init = 0; // WiFi栈初始化标志
// 如果已经初始化
if (1 == stack_wifi_init)
{
blog_info("Wi-Fi Stack Started already!!!"); // 打印已启动信息
return;
}
stack_wifi_init = 1; // 设置已初始化
blog_info("Wi-Fi init successful"); // 打印初始化成功信息
hal_wifi_start_firmware_task(); // 启动WiFi固件任务
/* 触发启动WiFi */
aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0); // 发送初始化完成事件
vTaskDelete(NULL); // 删除当前任务
}
用AP开启一个静态网页去连接WIFI
- 启用ap模式,ssid: anthinker password:12345678 ip地址为192.168.169.1
- 手机或电脑访问http://192.168.169.1
- 输入要配置的SSID 和 PASSWORD
- 点击连接,成功后静态页面就不可用了。
#include <FreeRTOS.h>
#include <aos/kernel.h>
#include <aos/yloop.h>
#include <blog.h>
#include <hal_wifi.h>
#include <lwip/inet.h>
#include <lwip/netif.h>
#include <lwip/tcpip.h>
#include <stdio.h>
#include <string.h>
#include <task.h>
#include <wifi_mgmr_ext.h>
#include "lwip/api.h"
#include "lwip/err.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"
#include "portmacro.h"
#include "string.h"
#include "web_server.h"
#include <cJSON.h>
#include <stdint.h>
#define SERVER_PORT 80
#define AP_SSID "ai-thinker"
#define AP_PWD "12345678"
#define TAG "softAP"
TaskHandle_t ap_task_handle = NULL;
char *ssid = NULL; //等带从网页中配置
char *password = NULL;
const char html_page[] =
"<!DOCTYPE html>\r\n"
"<html lang=\"zh\">\r\n"
"<head>\r\n"
" <meta charset=\"UTF-8\">\r\n"
" <meta name=\"viewport\" content=\"width=device-width, "
"initial-scale=1.0\">\r\n"
" <title>WiFi 配网</title>\r\n"
" <style>\r\n"
" body { font-family: Arial, sans-serif; text-align: center; "
"margin: 50px; }\r\n"
" input, button { padding: 10px; font-size: 16px; margin: 5px; }\r\n"
" </style>\r\n"
" <script>\r\n"
" function connectWiFi() {\r\n"
" let ssid = document.getElementById(\"wifi-ssid\").value;\r\n"
" let password = "
"document.getElementById(\"wifi-password\").value;\r\n"
" if (!ssid) { alert(\"请输入 WiFi 名称(SSID)\"); return; "
"}\r\n"
" fetch(\"/connect_wifi\", {\r\n"
" method: \"POST\",\r\n"
" headers: { \"Content-Type\": \"application/json\" },\r\n"
" body: JSON.stringify({ ssid, password })\r\n"
" })\r\n"
" .then(response => response.text())\r\n"
" .then(result => alert(\"WiFi 连接结果: \" + result))\r\n"
" .catch(error => alert(\"WiFi 连接失败: \" + error));\r\n"
" }\r\n"
" </script>\r\n"
"</head>\r\n"
"<body>\r\n"
" <h2>WiFi 配网</h2>\r\n"
" <label>WiFi 名称 (SSID):</label>\r\n"
" <input type=\"text\" id=\"wifi-ssid\" placeholder=\"输入 WiFi "
"SSID\">\r\n"
" <br>\r\n"
" <label>WiFi 密码:</label>\r\n"
" <input type=\"password\" id=\"wifi-password\" placeholder=\"输入 WiFi "
"密码\">\r\n"
" <br>\r\n"
" <button onclick=\"connectWiFi()\">连接 WiFi</button>\r\n"
"</body>\r\n"
"</html>\r\n";
static wifi_conf_t ap_conf = {
.country_code = "CN",
};
static wifi_interface_t ap_interface;
/**
* @brief wifi_ap_ip_set
* Set the IP address of soft AP
* @param ip_addr IPV4 addr
* @param netmask netmask
* @param gw DNS
*/
static void wifi_ap_ip_set(char *ip_addr, char *netmask, char *gw) {
struct netif *ap_netif = netif_find("ap1");
int i = 0;
int ap_ipaddr[4] = {0};
int ap_netmask[4] = {255, 255, 255, 0};
int ap_gw_arry[4] = {0, 0, 0, 0};
ap_ipaddr[0] = atoi(strtok(ip_addr, "."));
for (i = 1; i < 4; i++) {
ap_ipaddr[i] = atoi(strtok(NULL, "."));
}
if (netmask) {
ap_netmask[0] = atoi(strtok(netmask, "."));
for (i = 1; i < 4; i++)
ap_netmask[i] = atoi(strtok(NULL, "."));
}
if (gw) {
ap_gw_arry[0] = atoi(strtok(gw, "."));
for (i = 1; i < 4; i++)
ap_gw_arry[i] = atoi(strtok(NULL, "."));
}
if (ap_netif) {
ip_addr_t ap_ip;
ip_addr_t ap_mask;
ip_addr_t ap_gw;
IP4_ADDR(&ap_ip, ap_ipaddr[0], ap_ipaddr[1], ap_ipaddr[2], ap_ipaddr[3]);
IP4_ADDR(&ap_mask, ap_netmask[0], ap_netmask[1], ap_netmask[2],
ap_netmask[3]);
IP4_ADDR(&ap_gw, ap_gw_arry[0], ap_gw_arry[1], ap_gw_arry[2],
ap_gw_arry[3]);
netif_set_down(ap_netif);
netif_set_ipaddr(ap_netif, &ap_ip);
netif_set_netmask(ap_netif, &ap_mask);
netif_set_gw(ap_netif, &ap_gw);
netif_set_up(ap_netif);
blog_info("[softAP]:SSID:%s,PASSWORD:%s,IP addr:%s", AP_SSID, AP_PWD,
ip4addr_ntoa(netif_ip4_addr(ap_netif)));
} else
blog_info("no find netif ap1 ");
}
/**
* @brief wifi_ap_start
*
*/
static void wifi_ap_start() {
ap_interface = wifi_mgmr_ap_enable();
wifi_mgmr_conf_max_sta(4);
wifi_mgmr_ap_start(ap_interface, AP_SSID, 0, AP_PWD, 6);
wifi_ap_ip_set(
"192.168.169.1", "255.255.255.0",
"192.168.169.1"); // defaut gateway ip is "192.168.169.1",if you want usb
// other gateway ip ,please change
// components/network/lwip_dhcpd/dhcp_server_raw.c:42
// DHCPD_SERVER_IP for example, gateway ip:"192.168.4.1"
// , change DHCPD_SERVER_IP to "192.168.4.1" :
// wifi_ap_ip_set("192.168.4.1", "255.255.255.0",
// "192.168.4.1");
// components/network/lwip_dhcpd/dhcp_server_raw.c:42
// #define DHCPD_SERVER_IP "192.168.4.1"
}
// WiFi 连接函数,STA连接到指定的SSID和密码
int wifi_sta_connect(char *ssid, char *password) {
wifi_interface_t wifi_interface;
wifi_interface = wifi_mgmr_sta_enable(); // 启用 WiFi STA 模式
return wifi_mgmr_sta_connect(wifi_interface, ssid, password, NULL, NULL, 0,
0); // 连接WiFi
//
}
// 处理 WiFi 连接请求
static void handle_connect_wifi(struct netconn *conn, char *buf,
uint16_t buflen) {
printf("📡 收到 WiFi 连接请求...\n");
// 1️⃣ 查找 HTTP 请求体(JSON 数据)
char *json_start = strstr(buf, "\r\n\r\n"); // 找到 HTTP 头部结束位置
if (!json_start) {
printf("❌ 无法找到 HTTP 请求体\n");
netconn_write(conn,
"HTTP/1.1 400 Bad Request\r\nContent-Type: "
"text/plain\r\n\r\n请求格式错误",
62, NETCONN_NOCOPY);
return;
}
json_start += 4; // 跳过 "\r\n\r\n"
printf("🌍 提取的 JSON 数据: %s\n", json_start); // 调试信息
// 2️⃣ 解析 JSON 数据
cJSON *json = cJSON_Parse(json_start);
if (!json) {
printf("❌ JSON 解析失败\n");
netconn_write(conn,
"HTTP/1.1 400 Bad Request\r\nContent-Type: "
"text/plain\r\n\r\nJSON 解析失败",
62, NETCONN_NOCOPY);
return;
}
// 3️⃣ 获取 WiFi SSID 和密码
cJSON *ssid_item = cJSON_GetObjectItem(json, "ssid");
cJSON *password_item = cJSON_GetObjectItem(json, "password");
if (!ssid_item || !password_item) {
printf("❌ 缺少 SSID 或密码字段\n");
cJSON_Delete(json);
netconn_write(conn,
"HTTP/1.1 400 Bad Request\r\nContent-Type: "
"text/plain\r\n\r\n缺少必要参数",
62, NETCONN_NOCOPY);
return;
}
char *ssid = ssid_item->valuestring;
char *password = password_item->valuestring;
printf("📶 解析 WiFi SSID: %s\n", ssid);
printf("🔑 解析 WiFi 密码: %s\n", password);
cJSON_Delete(json);
// 4️⃣ 切换到 STA 模式并连接 WiFi
printf("🔄 切换到 STA 模式...\n");
int ret = wifi_sta_connect(ssid, password);
if (ret == 0) {
printf("✅ WiFi 连接请求已发送\n");
netconn_write(
conn,
"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nWiFi 连接中...", 59,
NETCONN_NOCOPY);
} else {
printf("❌ WiFi 连接失败,错误码: %d\n", ret);
netconn_write(conn,
"HTTP/1.1 500 Internal Server Error\r\nContent-Type: "
"text/plain\r\n\r\nWiFi 连接失败",
67, NETCONN_NOCOPY);
}
}
// 处理 HTTP 请求
static void web_httpserver(struct netconn *conn) {
struct netbuf *inputbuf;
char *buf;
uint16_t buflen;
err_t err;
err = netconn_recv(conn, &inputbuf);
if (err != ERR_OK) {
printf("❌ HTTP 请求接收失败\n");
netconn_close(conn);
return;
}
netbuf_data(inputbuf, (void **)&buf, &buflen);
printf("🌐 收到 HTTP 请求: %s\n", buf);
// 访问主页(返回 HTML)
if (strncmp(buf, "GET / ", 6) == 0) {
printf("📄 发送 HTML 页面\n");
netconn_write(conn, html_page, strlen(html_page), NETCONN_NOCOPY);
}
// 处理 WiFi 连接请求
else if (strncmp(buf, "POST /connect_wifi", 18) == 0) {
printf("🔄 处理 WiFi 连接请求...\n");
handle_connect_wifi(conn, buf, buflen);
} else {
printf("🚫 未知请求\n");
}
netbuf_delete(inputbuf);
netconn_close(conn);
}
// 启动 HTTP 服务器
void start_ap_http_server(void *pvParameters) {
struct netconn *conn, *newconn;
err_t err;
conn = netconn_new(NETCONN_TCP);
netconn_bind(conn, NULL, 80);
netconn_listen(conn);
while (1) {
err = netconn_accept(conn, &newconn);
if (err == ERR_OK) {
web_httpserver(newconn);
netconn_delete(newconn);
}
}
}
static void event_cb_wifi_event(input_event_t *event, void *private_data) {
switch (event->code) {
case CODE_WIFI_ON_INIT_DONE:
blog_info("<<<<<<<<< init wifi done <<<<<<<<<<");
wifi_mgmr_start_background(&ap_conf);
break;
case CODE_WIFI_ON_MGMR_DONE:
blog_info("<<<<<<<<< startting soft ap <<<<<<<<<<<");
wifi_ap_start();
break;
case CODE_WIFI_ON_AP_STARTED: // ap成功启动
blog_info("<<<<<<<<< startt soft ap OK<<<<<<<<<<<");
// 开启一个配网HTML页面
xTaskCreate(&start_ap_http_server, "server_task", 1024 * 10, NULL, 5, &ap_task_handle);
break;
case CODE_WIFI_ON_AP_STOPPED:
break;
case CODE_WIFI_ON_AP_STA_ADD: // 从设备连接到wb2的ap
blog_info("<<<<<<<<< station connent ap <<<<<<<<<<<");
break;
case CODE_WIFI_ON_AP_STA_DEL:
blog_info("<<<<<<<<< station disconnet ap <<<<<<<<<<<");
break;
case CODE_WIFI_ON_SCAN_DONE: {
printf("[APP] [EVT] SCAN Done %lld\r\n", aos_now_ms());
// wifi_mgmr_cli_scanlist();
} break;
case CODE_WIFI_ON_DISCONNECT: {
printf("[APP] [EVT] disconnect %lld\r\n", aos_now_ms());
} break;
case CODE_WIFI_ON_CONNECTING: {
printf("[APP] [EVT] Connecting %lld\r\n", aos_now_ms());
} break;
case CODE_WIFI_CMD_RECONNECT: {
printf("[APP] [EVT] Reconnect %lld\r\n", aos_now_ms());
} break;
case CODE_WIFI_ON_CONNECTED: {
printf("[APP] [EVT] connected %lld\r\n", aos_now_ms());
} break;
case CODE_WIFI_ON_PRE_GOT_IP: {
printf("[APP] [EVT] connected %lld\r\n", aos_now_ms());
} break;
case CODE_WIFI_ON_GOT_IP: {
printf("[APP] [EVT] GOT IP %lld\r\n", aos_now_ms());
printf("[SYS] Memory left is %d Bytes\r\n", xPortGetFreeHeapSize());
// wifi connection succeeded, create tcp server task
//
printf("successfuly connect!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
//到这一步就已经配网成功了,删不删除原来的AP任务都行
if (ap_task_handle != NULL) {
vTaskDelete(ap_task_handle);
ap_task_handle = NULL; // 避免悬空指针
}
// 在这里添加配网后的任务吧
} break;
case CODE_WIFI_ON_PROV_SSID: {
printf("[APP] [EVT] [PROV] [SSID] %lld: %s\r\n", aos_now_ms(),
event->value ? (const char *)event->value : "UNKNOWN");
if (ssid) {
vPortFree(ssid);
ssid = NULL;
}
ssid = (char *)event->value;
} break;
case CODE_WIFI_ON_PROV_BSSID: {
printf("[APP] [EVT] [PROV] [BSSID] %lld: %s\r\n", aos_now_ms(),
event->value ? (const char *)event->value : "UNKNOWN");
if (event->value) {
vPortFree((void *)event->value);
}
} break;
case CODE_WIFI_ON_PROV_PASSWD: {
printf("[APP] [EVT] [PROV] [PASSWD] %lld: %s\r\n", aos_now_ms(),
event->value ? (const char *)event->value : "UNKNOWN");
if (password) {
vPortFree(password);
password = NULL;
}
password = (char *)event->value;
} break;
case CODE_WIFI_ON_PROV_CONNECT: {
printf("[APP] [EVT] [PROV] [CONNECT] %lld\r\n", aos_now_ms());
printf("connecting to %s:%s...\r\n", ssid, password);
wifi_sta_connect(ssid, password);
} break;
case CODE_WIFI_ON_PROV_DISCONNECT: {
printf("[APP] [EVT] [PROV] [DISCONNECT] %lld\r\n", aos_now_ms());
} break;
default:
break;
}
}
static void proc_main_entry(void *pvParameters) {
aos_register_event_filter(EV_WIFI, event_cb_wifi_event, NULL);
hal_wifi_start_firmware_task();
aos_post_event(EV_WIFI, CODE_WIFI_ON_INIT_DONE, 0);
vTaskDelete(NULL);
}
static void system_thread_init() { /*nothing here*/ }
void main() {
system_thread_init();
puts("[OS] Starting TCP/IP Stack...");
tcpip_init(NULL, NULL);
puts("[OS] proc_main_entry task...");
xTaskCreate(proc_main_entry, (char *)"main_entry", 1024, NULL, 15, NULL);
}
效果
ap+sta效果


附件
附件:Apstaconf.zip