1、AliOS Things Wi-Fi 聯網背景
接入Wi-Fi網絡,是大部分IoT設備聯網的第一步。
接入Wi-Fi一般需要經歷配網和連網兩個階段。
1.1、Netmgr介紹
本文介紹的Netmgr模塊是將Wi-Fi驅動的配網和連網能力抽象提取出來,方便IoT設備快速入網連雲。
Wi-Fi設備需要連接到Wi-Fi熱點(Wi-Fi AP)之後才能與其它設備進行基於IP的通信, 我們將Wi-Fi設備獲取到Wi-Fi熱點的SSID/密碼的步驟稱為Wi-Fi配網。對於手機/電腦/平板而言, 用戶可以通過鍵盤或者觸摸屏輸入Wi-Fi熱點的SSID/密碼。但是對於沒有鍵盤, 沒有觸摸屏的IoT設備而言, 如何獲取Wi-Fi熱點的SSID/密碼是實現設備網絡管理的第一個關鍵步驟。
1.2、配網
簡要介紹下如下的兩種配網方式:
1、零配:不需要用戶輸入熱點信息的配網方案, 它是讓一個已連接到上網熱點的設備將熱點的SSID/密碼發送給待配網的設備。
2、一鍵配網:手機APP把相應信息打包到802.11數據包的特定區域,發送到周圍環境中;智能設備的Wi-Fi模塊處於混雜模式(Promiscuous Model)下,監聽網絡中的所有報文,直到解析出需要的信息(之前雙方約定好數據格式)。
更多配網信息,可以參考文章:
1.3、連網
無論哪種方式配網, 最終目的都是拿到SSID/PASSWORD,連上AP, 接入網絡。
終端設備要成功連上Wi-Fi需要經過三個階段:
1)掃描階段(SCAN);
2)認證階段 (Authentication);
3)關聯(Association)。
關聯成功後,終端設備發起DHCP請求或者使用靜態IP地址,就表示連網成功。
2、重要Netmgr API
Netmgr提供了一組API支持方便用戶快速接入AP。
2.1、netmgr_service_init
初始化netmgr模塊
函數原型
int netmgr_service_init(utask_t *task);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
task | 目前只需傳入NULL | NULL |
返回參數
0,成功
小於0, 失敗
2.2、netmgr_service_deinit
反初始化netmgr
函數原型
void netmgr_service_deinit(void);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
無 | 無 | 無 |
返回參數
無
2.3、netmgr_add_dev
添加netmgr設備
函數原型
int netmgr_add_dev(const char* name);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
name | 添加完整的設備路徑名 | "/dev/wifi0" |
返回參數
0,成功
小於0, 失敗
2.4、netmgr_get_dev
根據完整的設備路徑名獲取設備的netmgr句柄
函數原型
netmgr_hdl_t netmgr_get_dev(const char* name);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
name | 添加完整的設備路徑名 | "/dev/wifi0" |
返回參數
大於等於0,成功
小於0, 失敗
2.5、netmgr_set_ifconfig
設置網卡相關的信息
函數原型
int netmgr_set_ifconfig(netmgr_hdl_t hdl, netmgr_ifconfig_info_t* info);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
info | 設置的網卡配置信息 | 無 |
返回參數
0,成功
小於0, 失敗
備註:
以下是netmgr_ifconfig_info_t的結構體,其中rssi不支持設置,只支持讀取。
#define IPADDR_STR_LEN 16
/** @brief this struct defines netmgr ifconfig info */
typedef struct netmgr_ifconfig_info {
bool dhcp_en; /**< dhcp is enabled */
char ip_addr[IPADDR_STR_LEN]; /**< ip address */
char mask[IPADDR_STR_LEN]; /**< ip address mask */
char gw[IPADDR_STR_LEN]; /**< gateway ip address */
char dns_server[IPADDR_STR_LEN]; /**< dns server address */
char mac[6]; /**< mac address */
int rssi; /**< rssi */
} netmgr_ifconfig_info_t;
2.6、netmgr_get_ifconfig
設置網卡相關的信息
函數原型
int netmgr_get_ifconfig(netmgr_hdl_t hdl, netmgr_ifconfig_info_t* info);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
info | 獲取的網卡配置信息 | 無 |
返回參數
0,成功
小於0, 失敗
2.7、netmgr_set_auto_reconnect
啟動netmgr
函數原型
void netmgr_set_auto_reconnect(netmgr_hdl_t hdl, bool enable);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
enable | 是否自動發起Wi-Fi連網 | 無 |
返回參數
無
備註
當參數autoconfig是true時,使能自動連接Wi-Fi功能。如果設備有過成功連接AP的記錄,會自動去連成功鏈接過的AP記錄裡的SSID和Password。如果設備沒有成功連接AP的記錄,就不會自動去發起連網動作。當參數autoconfig是false時,關閉自動連接AP的功能,也不會去連AP。
2.8、netmgr_connect
連接網絡
函數原型
int netmgr_connect(netmgr_hdl_t hdl, netmgr_connect_params_t* params);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
params | 網絡連接參數 | 無 |
返回參數
0,成功
其他,失敗
備註:
netmgr_connect_params_t結構體目前只支持Wi-Fi,未來我們會補其其他連接方式。
/** @brief network type */
typedef enum {
NETMGR_TYPE_WIFI,
NETMGR_TYPE_GPRS,
NETMGR_TYPE_NBIOT,
NETMGR_TYPE_ETH,
NETMGR_TYPE_MAX
} netmgr_type_t;
/** @brief netmgr wifi connect params */
typedef struct netmgr_wifi_conenct_params {
char ssid[NETMGR_SSID_MAX_LEN+1]; /**< wifi ssid to connect*/
char pwd[NETMGR_PWD_MAX_LEN+1]; /**< wifi password to connect */
char bssid[NETMGR_BSSID_MAX_LEN]; /**< wifi bssid to connect */
int timeout; /**< wifi connect timeout */
} netmgr_wifi_connect_params_t;
/** @brief netmgr connect params */
typedef struct netmgr_connect_params {
netmgr_type_t type;
union {
netmgr_wifi_connect_params_t wifi_params; /**< wifi connect params */
} params;
} netmgr_connect_params_t;
2.9、netmgr_disconnect
斷開網絡
函數原型
int netmgr_disconnect(netmgr_hdl_t hdl);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
返回參數
0,成功
其他,失敗
2.10、netmgr_get_state
獲取當前網絡的狀態
函數原型
int netmgr_get_state(netmgr_hdl_t hdl);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
返回參數
typedef enum netmgr_conn_state{
CONN_STATE_DISCONNECTING,
CONN_STATE_DISCONNECTED,
CONN_STATE_CONNECTING,
CONN_STATE_CONNECTED,
CONN_STATE_OBTAINING_IP,
CONN_STATE_NETWORK_CONNECTED,
CONN_STATE_FAILED,
CONN_STATE_UNKNOWN
} netmgr_conn_state_t;
2.11、netmgr_save_config
保存網絡配置
函數原型
int netmgr_save_config(netmgr_hdl_t hdl);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
返回參數
0,成功
其他,失敗
備註:
一般在連網成功後,保存配置文件。
2.12、netmgr_get_config
獲取netmgr配置文件
函數原型
int netmgr_get_config(netmgr_hdl_t hdl, netmgr_config_t* config);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
config | netmgr配置信息 | 無 |
返回參數
0,成功
其他,失敗
備註:
/** @brief this struct defines wifi ap info */
typedef struct {
char ssid[NETMGR_SSID_MAX_LEN+1]; /**< ssid of wifi ap */
uint8_t pwd[NETMGR_PWD_MAX_LEN+1]; /**< password of wifi ap */
uint8_t bssid[NETMGR_BSSID_MAX_LEN]; /**< bssid of wifi ap */
int8_t ap_power; /**< signal strength of wifi ap */
uint8_t channel; /**< signal channel of wifi ap */
uint8_t sec_type; /**< details see netmgr_wifi_sec_type */
bool contain_chinese; /**< true:contain chinese false:no chinese */
netmgr_ssid_format_e ssid_format; /**< ssid string format */
char gbk_ssid[NETMGR_SSID_MAX_LEN+1]; /**< gbk ssid string */
} netmgr_wifi_ap_info_t;
/** @brief this struct defines wifi ap config */
typedef struct {
int ap_num; /**< ap number of array */
int used_ap; /**< ap that is used in the array */
netmgr_wifi_ap_info_t config[MAX_AP_CONFIG_NUM]; /**< The ap information array */
} netmgr_wifi_ap_config_t, netmgr_wifi_config_t;
/** @brief netmgr config struct */
typedef struct netmgr_config {
netmgr_type_t type;
union {
netmgr_wifi_config_t wifi_config; /**< wifi config struct */
//netmgr_gprs_config_t gprs_config;
//netmgr_nbiot_config_t nbiot_config;
//netmgr_eth_config_t eth_config;
} config;
} netmgr_config_t;
2.13、netmgr_del_config
刪除netmgr配置文件
函數原型
int netmgr_del_config(netmgr_hdl_t hdl, netmgr_del_config_t* config);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
config | netmgr配置信息 | 無 |
返回參數
0,成功
其他,失敗
備註:
/** @brief netmgr delete config */
typedef struct netmgr_del_config {
netmgr_type_t type;
union {
char ssid[NETMGR_SSID_MAX_LEN+1]; /**< wifi ssid to delete */
} config;
} netmgr_del_config_t;
2.14、netmgr_set_msg_cb
設置消息回調函數
函數原型
int netmgr_set_msg_cb(netmgr_hdl_t hdl, netmgr_msg_cb_t cb);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
cb | 消息回調函數 | 無 |
返回參數
0,成功
其他,失敗
備註:
/** @brief netmgr message type */
typedef enum {
NETMGR_MSGID_MIN = 0,
NETMGR_MSGID_WIFI_STATUS = NETMGR_MSGID_MIN,
NETMGR_MSGID_WIFI_STATUS_FROM_IMPL,
NETMGR_MSGID_WIFI_TRACE_FROM_IMPL,
NETMGR_MSGID_NETWORK_STATUS,
NETMGR_MSGID_ETH_STATUS_FROM_IMPL,
NETMGR_MSGID_MAX
} netmgr_msgid_t;
/** @brief this struct defines netmgr message */
typedef struct {
netmgr_msgid_t id; /**< netmgr msg id */
union {
int status; /**< reason of status change */
void *network_status_change; /**< msg content of status change */
void *trace;
} data;
} netmgr_msg_t;
/** @brief this struct defines netmgr message callback function */
typedef void (*netmgr_msg_cb_t)(netmgr_msg_t* msg);
當netmgr msg id等於NETMGR_MSGID_WIFI_STATUS_FROM_IMPL, 上報的data是status,其取值定義在eventid.h, 詳細如下:
#define EVENT_NETMGR_BASE 0x01000
#define EVENT_NETMGR_WIFI_DISCONNECTED (EVENT_NETMGR_BASE + 1) // Connection disconected
#define EVENT_NETMGR_WIFI_SCAN_STARTED (EVENT_NETMGR_BASE + 2) // Scan start
#define EVENT_NETMGR_WIFI_SCAN_FAILED (EVENT_NETMGR_BASE + 3) // Scan failed
#define EVENT_NETMGR_WIFI_SCAN_DONE (EVENT_NETMGR_BASE + 4) // Scan failed
#define EVENT_NETMGR_WIFI_NETWORK_NOT_FOUND (EVENT_NETMGR_BASE + 5) // no AP found
#define EVENT_NETMGR_WIFI_AUTHENTICATING (EVENT_NETMGR_BASE + 6) // Authentication start
#define EVENT_NETMGR_WIFI_AUTH_REJECT (EVENT_NETMGR_BASE + 7) // Authentication rejected by AP
#define EVENT_NETMGR_WIFI_AUTH_TIMEOUT (EVENT_NETMGR_BASE + 8) // Authentication timeout with AP
#define EVENT_NETMGR_WIFI_ASSOCIATING (EVENT_NETMGR_BASE + 9) // Association starts
#define EVENT_NETMGR_WIFI_ASSOC_REJECT (EVENT_NETMGR_BASE + 10) // Association rejected by AP
#define EVENT_NETMGR_WIFI_ASSOC_TIMEOUT (EVENT_NETMGR_BASE + 11) // Association timeout with AP
#define EVENT_NETMGR_WIFI_ASSOCIATED (EVENT_NETMGR_BASE + 12) // Authentication succeed
#define EVENT_NETMGR_WIFI_4WAY_HANDSHAKE (EVENT_NETMGR_BASE + 13) // 4way-handshark start
#define EVENT_NETMGR_WIFI_HANDSHAKE_FAILED (EVENT_NETMGR_BASE + 14) // 4way-handshake fails
#define EVENT_NETMGR_WIFI_4WAY_HANDSHAKE_DONE (EVENT_NETMGR_BASE + 15) // 4way-handshark done
#define EVENT_NETMGR_WIFI_GROUP_HANDSHAKE (EVENT_NETMGR_BASE + 16) // group-handshark start
#define EVENT_NETMGR_WIFI_GROUP_HANDSHAKE_DONE (EVENT_NETMGR_BASE + 17) // group-handshark done = completed
#define EVENT_NETMGR_WIFI_CONNECTED (EVENT_NETMGR_BASE + 18) // Connection to AP done
#define EVENT_NETMGR_WIFI_CONN_TIMEOUT (EVENT_NETMGR_BASE + 19) // Connection timeout
#define EVENT_NETMGR_WIFI_DEAUTH (EVENT_NETMGR_BASE + 20) // Deauth received from AP
#define EVENT_NETMGR_WIFI_MAX (EVENT_NETMGR_WIFI_DEAUTH)
#define EVENT_NETMGR_DHCP_BASE (EVENT_NETMGR_WIFI_MAX)
#define EVENT_NETMGR_DHCP_START_FAILED (EVENT_NETMGR_DHCP_BASE + 1) // DHCP start fails
#define EVENT_NETMGR_DHCP_TIMEOUT (EVENT_NETMGR_DHCP_BASE + 2) // DHCP timeout
#define EVENT_NETMGR_DHCP_SUCCESS (EVENT_NETMGR_DHCP_BASE + 3) // DHCP success
#define EVENT_NETMGR_DHCP_MAX (EVENT_NETMGR_DHCP_SUCCESS)
#define EVENT_NETMGR_SNTP_BASE (EVENT_NETMGR_DHCP_MAX)
#define EVENT_NETMGR_SNTP_SUCCESS (EVENT_NETMGR_SNTP_BASE + 1) // SNTP success
#define EVENT_NETMGR_SNTP_FAILED (EVENT_NETMGR_SNTP_BASE + 2 ) // SNTP failure
#define EVENT_NETMGR_SNTP_MAX (EVENT_NETMGR_SNTP_FAILED)
#define EVENT_NETMGR_CONN_BASE (EVENT_NETMGR_SNTP_MAX)
#define EVENT_NETMGR_CONN_RECONNECT (EVENT_NETMGR_CONN_BASE + 1) // Reconnect AP
#define EVENT_NETMGR_CONN_MAX (EVENT_NETMGR_CONN_RECONNECT)
#define EVENT_NETMGR_GOT_IP (EVENT_NETMGR_DHCP_SUCCESS)
#define EVENT_NETMGR_NET_BASE (EVENT_NETMGR_CONN_MAX)
#define EVENT_NETMGR_NET_DISCON (EVENT_NETMGR_WIFI_DISCONNECTED)
#define EVENT_NETMGR_NET_CONFIG (EVENT_NETMGR_NET_BASE + 1)
#define EVENT_NETMGR_MAX (EVENT_NETMGR_NET_CONFIG)
當netmgr msg id等於NETMGR_MSGID_NETWORK_STATUS,上報的data是network_status_change,其對應的結構體如下:
#define NETMGR_WIFI_METHOD_MAX_LENGTH (32)
#define NETMGR_WIFI_STATUS_MAX_LENGTH (32)
#define NETMGR_WIFI_SSID_MAX_LENGTH (32)
#define NETMGR_WIFI_PASSWORD_MAX_LENGTH (64)
/** @brief this struct defines netmgr wifi status change info */
typedef struct {
char method[NETMGR_WIFI_METHOD_MAX_LENGTH+1]; /**< status change method */
int quantity; /**< signal quantity */
char status[NETMGR_WIFI_STATUS_MAX_LENGTH+1]; /**< current status */
char ssid[NETMGR_WIFI_SSID_MAX_LENGTH+1]; /**< ssid of wifi */
char password[NETMGR_WIFI_PASSWORD_MAX_LENGTH+1]; /**< password of wifi */
uint8_t reason_code; /**< reason of status change */
} netmgr_wifi_network_status_change_t;
2.15、netmgr_del_msg_cb
刪除消息回調函數
函數原型
int netmgr_del_msg_cb(netmgr_hdl_t hdl, netmgr_msg_cb_t cb);
參數列表
參數名稱 | 參數描述 | 參數示例 |
---|---|---|
hdl | netmgr句柄 | 無 |
cb | 消息回調函數 | 無 |
返回參數
0,成功
其他,失敗
3、API使用範例
3.1、直接連網
注意:netmgr內部需要event service的支持,所以需要在調用netmgr_service_init函數初始化netmgr的同時,調用event_service_init初始化函數。
使用event_subscribe註冊監聽的是特定的事件,而netmgr_set_msg_cb可以監聽netmgr支持的所有事件。
#include "netmgr.h"
#include <uservice/uservice.h>
#include <uservice/eventid.h>
const char* ssid = "aos";
const char* passwd = "123456";
static void wifi_event_cb(uint32_t event_id, const void *param, void *context)
{
printf("Got IP\r\n");
}
static void netmgr_comp_example()
{
netmgr_connect_params_t netmgr_params;
netmgr_hdl_t netmgr_handle;
printf("netmgr test \r\n");
event_service_init(NULL);
netmgr_service_init(NULL);
event_subscribe(EVENT_NETMGR_DHCP_SUCCESS, wifi_event_cb, NULL);
memset(&netmgr_params, 0, sizeof(netmgr_connect_params_t));
strncpy(netmgr_params.params.wifi_params.ssid, ssid, NETMGR_SSID_MAX_LEN);
strncpy(netmgr_params.params.wifi_params.pwd, passwd, NETMGR_PWD_MAX_LEN);
netmgr_params.params.wifi_params.timeout = 5000;
netmgr_handle = netmgr_get_dev("/dev/wifi0");
if(netmgr_handle < 0) {
printf("get netmgr handle failed\n");
return;
}
if(netmgr_connect(netmgr_handle, &netmgr_params) != 0) {
printf("netmgr connect failed");
return;
}
}
3.2、使用歷史記錄連網
#include "netmgr.h"
void start_netmgr(void) {
printf("netmgr test \r\n");
event_service_init(NULL);
netmgr_service_init(NULL);
netmgr_set_auto_reconnect(true);
}
3.3、使用netmgr範例
以上範例中註冊了一個wifi_event_cb函數來監聽事件,EVENT_NETMGR_DHCP_SUCCESS,表示成功獲取到了IP地址。
將以上範例中的netmgr_comp_example函數加到文件solutions/helloworld_demo/helloworld.c。
int application_start(int argc, char *argv[])
int count = 0;
printf("nano entry here!\r\n");
netmgr_comp_example();
while(1) {
printf("hello world! count %d \r\n", count++);
aos_msleep(1000);
};
}
3.4、添加netmgr模塊
solutions/helloworld_demo/package.yaml文件裡第二部分:依賴信息里加上 netmgr組件
## 第二部分:依賴信息
# 指定該組件依賴的組件及版本,版本支持條件比較,支持:>=v1.0, >v1.0, ==v1.0, <=v1.0, <v1.0, v1.0
# 未指定條件時,默認為 ==,如 v1.0 與 ==v1.0
# depends: # <可選項> 該組件依賴其他的組件,合理的依賴才能保證組件能編譯、使用
# - minilibc: v7.2.0
# - aos: >=v7.2.0
depends:
- init: dev_aos
- cli: dev_aos
- osal_aos: dev_aos
- haas100: dev_aos
- netmgr: dev_aos
4、Netmgr命令
4.1、簡介
支持使用命令的方式對Wi-Fi連網相關的操作,如,對存儲的連接信息的讀/寫/刪除,打印當前網絡內的所有AP的信息,連接AP,斷開AP的連接,查詢網絡狀態等。
命令行 | 說明 |
---|---|
netmgr -t wifi -i | 初始化 |
netmgr -t wifi -a [0/1] | 設置是否自動重連。0,不自動重連;1,自動重連。 |
netmgr -t wifi -b [0/1] | 是否保存歷史連接記錄。0,不保存歷史連接記錄。1,保存歷史連接記錄。 |
netmgr -t wifi -c [ssid] [password] | 使用ssid password連網 |
netmgr -t wifi -e | 斷開Wi-Fi連接 |
netmgr -t wifi -m | 設置MAC地址 |
netmgr -t wifi -s | 打印當前網絡上的AP的信息 |
netmgr -t wifi -p | 打印當前網絡狀態 |
netmgr -t wifi -r | 讀Wi-Fi配置文件 |
netmgr -t wifi -w [wifi_config] | 寫Wi-Fi配置文件。wifi_config格式,如,network={\nssid=\"apple\"\npassword=\"aos123456\"\nchannel=\"1\"\n}\n |
netmgr -t wifi -d | 刪除Wi-Fi配置文件 |
netmgr -t wifi -n | 1, 使能sntp;2,關閉sntp。目前沒有查詢sntp狀態的參數,默認是sntp功能打開。 |
4.2、命令範例
使用如下命令可以快速連SSID是"aos" 密碼是"123456"的AP。
netmgr -t wifi -i
netmgr -t wifi -b 1
netmgr -t wifi -a 1
netmgr -t wifi -c aos 123456
也可以手動寫入配置命令,使用如下的命令連網。其中,如果無法確定AP的channel信息,使用0進行全網段掃描。
netmgr -t wifi -i
netmgr -t wifi -w network={\\nssid=\"apple\"\\npassword=\"aos123456\"\\nchannel=\"1\"\\n}\\n
netmgr -t wifi -a 1
開發者支持
HaaS解決方案中心:https://haas.iot.aliyun.com/
HaaS技術社區:https://blog.csdn.net/HaaSTech
開發者釘釘群和公眾號見下圖,開發者釘釘群每天都有技術支持同學值班。