发帖
4 0 0

AI-WB2 配网【上】

WildboarG
论坛元老

21

主题

156

回帖

3542

积分

论坛元老

积分
3542
Ai-WB2系列 44 4 昨天 15:51

AI-WB2 配网【上】

Static Badge Static Badge Static Badge Static Badge

引言


早期的Wi-Fi设备大多都用于带屏幕和输入设备的(如嵌入式设备/笔记本/手机等),配网只需要用户连接路由器的SSID输入password即可。

但是随着物联网的兴起,Wi-Fi被大量应用于没有人机交互方式的设备中,如智能插座等物联网终端产品中,而Wi-Fi(IEEE802.11)标准在设计之初是没有考虑这种无人机交互方式的配网的,也就是没有官方标准。这也就导致了市面上配网的方法多种多样,且各家玩各家的,鱼龙混杂,互不相通,整体体验偏低。

简化示意图如下:

图片.png

常见的配网方式有:

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

用AP开启一个静态网页去连接WIFI

  1. 启用ap模式,ssid: anthinker password:12345678 ip地址为192.168.169.1
  2. 手机或电脑访问http://192.168.169.1
  3. 输入要配置的SSID 和 PASSWORD
  4. 点击连接,成功后静态页面就不可用了。
#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效果

截图2025-03-2516-25-54.png

截图2025-03-2516-26-00.png

附件

upload 附件:Apstaconf.zip

──── 0人觉得很赞 ────

使用道具 举报

图裂开了
昨天 16:21

论坛吞图
网页配网真方便,界面可以用AI写个代码美化一下
昨天 22:10
HaydenHu 发表于 2025-3-25 21:22
网页配网真方便,界面可以用AI写个代码美化一下

要啥自行车
您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 28168 个
  • 话题数: 39947 篇