由 WildboarG 贡献,Ai-Thinker 进行整理
AI-WB2 配网【上】
AI-WB2 html网页配网
引言
早期的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配网
STA STA配网原理就和你手机连接路由器一样简单。预先将路由器或者路由设备(能够产生热点的设备)开启,然后需要配网的设备(例如WB2/M61/ESP8266等)内部写入与之匹配固定的SSID与PASSWORD,当配网设备运行后,会扫描附近热点,一旦匹配到对应的SIID,将尝试连接,成功即可返回。
通常sta有动态获取和静态两种选项:
动态:由路由器DHCP随机分配未使用的IP地址
静态:预先将我想使用的ip地址写入程序中,连接后设置我要使用的ip地址。更方便些。
STA+AP
- 设备端(WB2/M61/ESP8266等)进入softAP模式,然后建立一个约定好的AP热点。
- 手机APP端/电脑 用户去连接步骤1中建立的热点。
- 连接后,手机与设备端建立局域网通信。
- 手机APP/电脑 通过UDP/TCP(常见的有静态网页)将配网信息(常见的是路由器)传递给设备。
- 设备端拿到配网信息之后切换为STA模式,用STA模式连接。
示例代码
- STA
📜 点击展开完整代码
C
#
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
📜 点击展开完整代码
C
// 定义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+STA
用AP开启一个静态网页去连接WIFI
- 启用ap模式,ssid: anthinker password:12345678 ip地址为192.168.169.1
- 手机或电脑访问<http://192.168.169.1>
- 输入要配置的SSID 和 PASSWORD
- 点击连接,成功后静态页面就不可用了。
📜 点击展开完整代码
C
#
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效果



