WiFi单品设备开发-基于认证模组
更新时间:2019-06-23 14:01:44
开发场景说明
本文的阅读对象是设备开发者,讲解设备开发者如何在通过阿里云IoT高级认证的WiFi模组上进行产品功能的开发,并将设备连接到飞燕平台。
不同的版本开发的接口可能存在差异,本文档基于AliOS Things 1.3.4版本进行编写。
开发过程
产品的开发过程如下图所示:
设备开发者需要安装AliOS Things的开发工具以及获取代码,配置运行的目标模组,然后进行产品功能的开发
开发环境设置
端侧开发者往往windows环境使用较多,接下来将介绍如何在安装了windows7的PC上搭建开发和烧写环境。
Windows下工具安装
体验者需要安装如下工具:
软件名称 | 功能描述 |
---|---|
python-2.7.14-x64.msi | python2.7环境 |
VSCodeSetup-x64-1.21.1.exe | 代码编辑工具 |
alios-studio.vsix | VSCode中的alios开发插件 |
cpptools.vsix | VSCode中C语言语法检测插件 |
Git-2.16.2-x64.exe | 控制台工具,用于执行aos-cube命令 |
FTDI_VCP_Driver.exe | FT232串口芯片驱动。用于模组烧写HF模组烧写 |
CP210x_Windows_Drivers | CP210X USB转串口芯片驱动,用于MK3080模组烧写 |
RDA Flashtest Tools | 固件烧写工具,用于HF-LPB130模组的固件烧写 |
ImageTool.exe | 固件烧写工具,用于MK3080模组的固件烧写 |
aos-cube | aos编译工具包。 |
完成软件安装后,打开vscode工具,在“文件”菜单中选择“首选项”->"设置",出现工具的配置文件,将如下代码拷贝到右侧的“用户设置”窗口中,将默认的终端设置为“Git bash”,请根据真实的bash安装地址调整bash.exe的路径。
{
"terminal.integrated.shell.windows": "C:\\Program Files\\Git\\bin\\bash.exe",
}
保存后关闭设置文件,在“查看”菜单中打开“集成终端”。可以看到vs code将bash作为其默认终端工具。
测试python安装情况,在终端中输入“python”命令,如果python安装正确,且环境变量设置正确,则可以看到如图的的输出
如果提示找不到命令,请将python2.7目录添加至环境变量中
点击桌面上的计算机图片,右击选择属性->选择高级系统设置;
选择环境变量按钮;
选择Path选项,点击"编辑",弹出窗口,在变量值框输入C:\Python27;
安装aos-cube
用 python 包管理器 pip
来安装 aos-cube
和相关的依赖包
在全局环境,以便于后续使用 AliOS Things Studio 进行开发。
在vs code的控制台中输入如下代码,安装aos-cube
$ pip install setuptools
$ pip install wheel
$ pip install aos-cube
在代码运行完成后在控制台中输入aos --version命令,验证安装是否成功。如果看到输出版本号,则表示安装成功。
获取AliOS Things代码
在vs code的控制台中,通过cd命令进入到自己希望放置代码的目录,然后执行如下命令,获取AliOS Things源码。
git clone https://github.com/alibaba/AliOS-Things.git
cd AliOS-Things
或通过https://github.com/alibaba/AliOS-Things.git连接访问github主页,通过zip方式下载源码,下载前请注意选择rel_1.3.4版本。
将下载的zip包解压后(或者通过git clone获得的源码目录),在VS code工具中打开AliOS Things文件夹。可以看到如此的画面。在vs code的终端中,通过cd命令进入与打开文件夹相同的路径。
验证aos是可以正常编译,下面是在庆科EMW3080模组上编译一个打印hello world程序示例:
aos make helloworld@mk3080
完成编译后,会在AliOS Things\out\helloworld@mk3080\binary目录下生成helloworld@mk3080.all.bin文件,该文件即为需要烧写的文件,用户可以将其烧写到3080模组上查看程序是否可以正常运行。
注:如果模组不是EMW3080,则替换上面命令中@之后的mk3080,用户可以查看目录board得知支持的模组。
将固件烧写到模组
在编译得到固件后,即可以将固件烧写到模组中执行,不同的模组烧写过程是不一样的,请联系模组厂商获取烧写工具以及烧写说明。
在生活物联网平台定义产品
下面的截图仅供参考,因为控制台的页面显示可能会发生变动。
创建产品
请登录“生活物联网平台”、并参照文档“创建产品”进行产品创建。当创建产品时,将会跳出下面的页面:
如果设备开发者不熟悉生活物联网平台的设备开发流程,建议客户首先创建一个“产品信息”中所属分类为“电工照明/灯”的产品进行熟悉
创建产品时:
“节点类型”请选择“设备”
“是否接入网关”选择“否”
“连网方式”选择“WiFi”
“数据格式”选择“ICA标准数据格式”
“使用ID2认证”选择“否”
功能定义
如果设备开发者不了解物模型,请阅读“物的模型”进行了解。
如果产品品类为灯,将显示下面的页面:
设备开发者可以在该页面上添加自定义的属性、服务、事件。
设备调试
在此步骤中,请选择选用的WiFi模组:
之后可以创建一个测试设备,请点击如下图所示的“新增测试设备”:
之后平台将为测试设备分配设备身份信息,如下图所示:
请将上图中的ProductKey、DeviceName、DeviceSecret复制到一个文件中待用。
人机交互
建议使能“使用公版App控制产品”,这样就可以使用生活物联网平台提供的“平台公版App”对设备进行控制,如下图所示:
批量投产
设备开发结束之后才会投产,开发阶段请不要点击“完成开发”
设备端产品开发
设备开发分为两个大步骤:
产品功能实现
WiFi配网
产品模型开发
对于WiFi设备来说,首先需要通过WiFi配网来获得WiFi热点的SSID/密码,而WiFI配网的移植和调试是比较花时间的,所以产品开发的时候可以产品功能开发和WiFi配网并行实现。
下面的代码将配网的代码注释掉,让设备直接去连接一个指定的热点,然后连接到阿里云物联网平台,从而可以开始进行产品物模型功能的开发与调试。被修改的函数start_netmgr()位于文件AliOS-Things/example/linkkitapp/app_entry.c中
int application_start(int argc, char **argv)
{
...
#if 0
#ifdef SUPPORT_DEV_AP
aos_task_new("dap_open", awss_open_dev_ap, NULL, 4096);
#else
aos_task_new("netmgr_start", start_netmgr, NULL, 4096);
#endif
#endif
//下面的代码让设备直接去连接一个指定SSID
netmgr_ap_config_t config;
strncpy(config.ssid, "your_ssid", sizeof(config.ssid) - 1);
strncpy(config.pwd, "your_ssid_password", sizeof(config.pwd) - 1);
netmgr_set_ap_config(&config);
netmgr_start(false);
...
}
还有另外一种方式,在调试阶段可以用cli命令进行配网:
netmgr connect ssid password
当设备连接到WiFi热点、获得一个IP地址之后会自动去连接阿里云IoT。
设备身份信息配置
在linkkit_example_solo.c的代码中设置了设备的身份信息,设备开发者需要将测试设备的信息对其进行替换:
// for demo only
#define PRODUCT_KEY "a15trrE4PqM"
#define PRODUCT_SECRET "4uZsr1uSnCwzhjPM"
#define DEVICE_NAME "IFn66CxbVIlOoOaI2cJy"
#define DEVICE_SECRET "qwvShyphCALzDy380ppcRnj0zNZFjc8S"
设备开发者将设备身份信息设置到程序之后,可以将代码进行编译并遵循模组商提供的烧写工具将固件写入模组,确保设备可以连接到阿里云物联网平台。如果模组提供串口打印输出,当模组连接到阿里云物联网平台后将会输出类似下面的信息提示:
如果模组可以正常连接阿里云物联网平台,在飞燕的商家后台可以看到这个设备已激活,以及设备连接到物联网平台的时间信息,如下图所示:
建议设备开发者先确保模组已经可以正常连接到阿里云物联网平台后,再继续进行下面物模型的实现。
注:在example中设备的身份信息是在代码中写死的,设备开发时需要通过HAL_GetProductKey()、HAL_GetDeviceName()、HAL_GetDeviceSecret()进行返回。
产品属性上报
产品的属性发生变化时,需要将变化后的数值上报到物联网平台。属性变化的检测以及上报是由设备开发者定义和实现的。
示例代码中对应的产品具有一个LightSwitch的属性,类型为bool;还具有一个RGBColor的属性,类型为复合型。在linkkit_example()函数中调用了函数user_post_property()用于上报相关属性,用户可以参考该代码实现产品的属性变化上报:
void user_post_property(void)
{
static int example_index = 0;
int res = 0;
user_example_ctx_t *user_example_ctx = user_example_get_ctx();
char *property_payload = "NULL";
if (example_index == 0) {
/* Normal Example */
property_payload = "{\"LightSwitch\":1}";
example_index++;
} else if (example_index == 1) {
/* Wrong Property ID */
property_payload = "{\"LightSwitchxxxx\":1}";
example_index++;
} else if (example_index == 2) {
/* Wrong Value Format */
property_payload = "{\"LightSwitch\":\"test\"}";
example_index++;
} else if (example_index == 3) {
/* Wrong Value Range */
property_payload = "{\"LightSwitch\":10}";
example_index++;
} else if (example_index == 4) {
/* Missing Property Item */
property_payload = "{\"RGBColor\":{\"Red\":45,\"Green\":30}}";
example_index++;
} else if (example_index == 5) {
/* Wrong Params Format */
property_payload = "\"hello world\"";
example_index++;
} else if (example_index == 6) {
/* Wrong Json Format */
property_payload = "hello world";
example_index = 0;
}
res = IOT_Linkkit_Report(user_example_ctx->master_devid, ITM_MSG_POST_PROPERTY,
(unsigned char *)property_payload, strlen(property_payload));
EXAMPLE_TRACE("Post Property Message ID: %d", res);
}
产品事件上报
如果产品定义了事件,当事件发生时也需要向云端发送事件。事件的检测以及上报由设备开发者实现。
示例产品定义了一个标识符为“Error”的事件,该事件还有一个标识符为“ErrorCode”的输出参数。下面的代码示例描述了如何向物联网平台发送一个事件:
void user_post_event(void)
{
static int example_index = 0;
int res = 0;
user_example_ctx_t *user_example_ctx = user_example_get_ctx();
char *event_id = "Error";
char *event_payload = "NULL";
if (example_index == 0) {
/* Normal Example */
event_payload = "{\"ErrorCode\":0}";
example_index++;
} else if (example_index == 1) {
/* Wrong Property ID */
event_payload = "{\"ErrorCodexxx\":0}";
example_index++;
} else if (example_index == 2) {
/* Wrong Value Format */
event_payload = "{\"ErrorCode\":\"test\"}";
example_index++;
} else if (example_index == 3) {
/* Wrong Value Range */
event_payload = "{\"ErrorCode\":10}";
example_index++;
} else if (example_index == 4) {
/* Wrong Value Range */
event_payload = "\"hello world\"";
example_index++;
} else if (example_index == 5) {
/* Wrong Json Format */
event_payload = "hello world";
example_index = 0;
}
res = IOT_Linkkit_TriggerEvent(user_example_ctx->master_devid, event_id, strlen(event_id),
event_payload, strlen(event_payload));
EXAMPLE_TRACE("Post Event Message ID: %d", res);
}
产品回调函数处理
在函数linkkit_example()中的linkkit_ops定义了系统的各种事件处理函数,如下面的代码所示:
int linkkit_example()
{
...
/* Register Callback */
IOT_RegisterCallback(ITE_CONNECT_SUCC, user_connected_event_handler);
IOT_RegisterCallback(ITE_DISCONNECTED, user_disconnected_event_handler);
IOT_RegisterCallback(ITE_RAWDATA_ARRIVED, user_down_raw_data_arrived_event_handler);
IOT_RegisterCallback(ITE_SERVICE_REQUST, user_service_request_event_handler);
IOT_RegisterCallback(ITE_PROPERTY_SET, user_property_set_event_handler);
IOT_RegisterCallback(ITE_PROPERTY_GET, user_property_get_event_handler);
IOT_RegisterCallback(ITE_REPORT_REPLY, user_report_reply_event_handler);
IOT_RegisterCallback(ITE_TRIGGER_EVENT_REPLY, user_trigger_event_reply_event_handler);
IOT_RegisterCallback(ITE_TIMESTAMP_REPLY, user_timestamp_reply_event_handler);
IOT_RegisterCallback(ITE_INITIALIZE_COMPLETED, user_initialized);
IOT_RegisterCallback(ITE_FOTA, user_fota_event_handler);
IOT_RegisterCallback(ITE_COTA, user_cota_event_handler);
};
关于回调函数的说明:
事件 | 回调函数原型 | 事件触发条件说明 |
---|---|---|
ITE_CONNECT_SUCC | int callback(void); | 与云端连接成功时 |
ITE_DISCONNECTED | int callback(void); | 与云端连接断开时 |
ITE_RAWDATA_ARRIVED | int callback(const int devid, const unsigned char *payload, const int payload_len); | Linkkit收到收到raw data数据时 |
ITE_SERVICE_REQUST | int callback(const int devid, const char _serviceid, const int serviceid_len, const char request, const int request_len, char _response, int *response_len); | Linkkit收到收到服务(同步/异步)调用请求时 |
ITE_PROPERTY_SET | int callback(const int devid, const char *request, const int request_len); | Linkkit收到收到属性设置请求时 |
ITE_PROPERTY_GET | int callback(const int devid, const char _request, const int request_len, char _response, int response_len); | Linkkit收到收到属性获取的请求时 |
ITE_REPORT_REPLY | int callback(const int devid, const int msgid, const int code, const char *reply, const int reply_len); | Linkkit收到收到上报消息的应答时 |
ITE_TRIGGER_EVENT_REPLY | int callback(const int devid, const int msgid, const int code, const char eventid, const int eventid_len, const char message, const int message_len); | Linkkit收到收到事件上报消息的应答时 |
ITE_TIMESTAMP_REPLY | int callback(const char *timestamp); | 当Linkkit收到收到查询时间戳请求的应答时 |
ITE_TOPOLIST_REPLY | int callback(const int devid, const int msgid, const int code, const char * payload, const int payload_len); | Linkkit收到收到查询拓扑关系请求的应答时 |
ITE_PERMIT_JOIN | int callback(const char * product_key, const int time); | Linkkit收到允许子设备入网的请求时 |
ITE_INITIALIZE_COMPLETED | int callback(const int devid); | 设备初始化完成时 |
ITE_FOTA | int callback(int type, const char *version); | Linkkit收到可用固件的通知时 |
ITE_COTA | int callback(int type, const char config_id, int config_size, const char get_type, const char sign, const char sign_method, const char *url); | Linkkit收到可用远程配置文件的通知时 |
主循环处理
在linkkit_example()中存在一个循环,其中IOT_Linkkit_Yield必须周期调用,用于linkkit业务处理;代码如下所示:
time_begin_sec = user_update_sec();
while (1) {
IOT_Linkkit_Yield(USER_EXAMPLE_YIELD_TIMEOUT_MS);
time_now_sec = user_update_sec();
if (time_prev_sec == time_now_sec) {
continue;
}
if (max_running_seconds && (time_now_sec - time_begin_sec > max_running_seconds)) {
EXAMPLE_TRACE("Example Run for Over %d Seconds, Break Loop!\n", max_running_seconds);
break;
}
/* Post Proprety Example */
if (time_now_sec % 11 == 0 && user_master_dev_available()) {
user_post_property();
}
/* Post Event Example */
if (time_now_sec % 17 == 0 && user_master_dev_available()) {
user_post_event();
}
/* Device Info Update Example */
if (time_now_sec % 23 == 0 && user_master_dev_available()) {
user_deviceinfo_update();
}
/* Device Info Delete Example */
if (time_now_sec % 29 == 0 && user_master_dev_available()) {
user_deviceinfo_delete();
}
/* Post Raw Example */
if (time_now_sec % 37 == 0 && user_master_dev_available()) {
user_post_raw_data();
}
time_prev_sec = time_now_sec;
}
其中还包含了下面一段演示代码,用于上报所有的属性、上报事件等,在实际产品开发时需要将其修改为设备商自己的逻辑,比如:
while (1) {
IOT_Linkkit_Yield(USER_EXAMPLE_YIELD_TIMEOUT_MS);
/* Post Proprety Example */
if (user_master_dev_available()) {
user_post_property();
}
/* Post Event Example */
if (user_master_dev_available()) {
user_post_event();
}
}
设备商完成自己物模型功能的代码编写之后,可以将固件编译出来并根据相关模组的烧写方法把固件烧写到模组上进行功能验证和调试。
WiFi配网开发
配网支持:
一键配网(Smartconfig):App直接给设备配网
手机热点配网(phone-config):App直接给设备配网
路由器热点配网(router-config):输出到路由器厂商/运营商
零配(zero-config):已配网设备为待配网设备配网
设备热点配网(dev-ap):设备开热点,手机连接设备热点完成为设备配网
蓝牙配网(ble-config):借助BT/BLE为设备配网
在开发WiFi配网的时候,请确保去除前面章节开发产品物模型时对start_netmgr()的修改:
static void start_netmgr(void *p)
{
/*
* register event callback to detect event of AWSS
*/
iotx_event_regist_cb(linkkit_event_monitor);
netmgr_start(true);
aos_task_exit(0);
}
开发过程说明
1.配网对外披露的API列表:
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#ifndef __IOT_EXPORT_AWSS_H__
#define __IOT_EXPORT_AWSS_H__
#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
/**
* @brief start wifi setup service
*
* @retval -1 : wifi setup fail
* @retval 0 : sucess
* @note: awss_config_press must been called to enable wifi setup service
*/
int awss_start();
/**
* @brief stop wifi setup service
*
* @retval -1 : failure
* @retval 0 : sucess
* @note
* if awss_stop is called before exit of awss_start, awss and notify will stop.
* it may cause failutre of awss and device bind.
*/
int awss_stop();
/**
* @brief make sure user touches device belong to themselves
*
* @retval -1 : failure
* @retval 0 : sucess
* @note: AWSS dosen't parse awss packet until user touch device using this api.
*/
int awss_config_press();
/**
* @brief start wifi setup service with device ap
*
* @retval -1 : failure
* @retval 0 : sucess
* @note
* 1. if awss_stop or awss_dev_ap_stop is called before exit of awss_dev_ap_start
* awss with device ap and notify will stop, it may cause failutre of device ap
* and device bind.
* 2. awss_dev_ap_start doesn't need to call awss_config_press to been enabled.
*/
int awss_dev_ap_start();
/**
* @brief stop wifi setup service with device ap
*
* @retval -1 : failure
* @retval 0 : sucess
* @note
* if awss_dev_ap_stop is called before exit of awss_dev_ap_start
* awss with device ap and notify will stop, it may cause failutre of device ap
*/
int awss_dev_ap_stop();
/**
* @brief report token to cloud after wifi setup success
*
* @retval -1 : failure
* @retval 0 : sucess
*/
int awss_report_cloud();
/**
* @brief report reset to cloud.
*
* @retval -1 : failure
* @retval 0 : sucess
* @note
* device will save reset flag if device dosen't connect cloud, device will fails to send reset to cloud.
* when connection between device and cloud is ready, device will retry to report reset to cloud.
*/
int awss_report_reset();
enum awss_event_t {
AWSS_START = 0x1000, // AWSS start without enbale, just supports device discover
AWSS_ENABLE, // AWSS enable
AWSS_LOCK_CHAN, // AWSS lock channel(Got AWSS sync packet)
AWSS_CS_ERR, // AWSS AWSS checksum is error
AWSS_PASSWD_ERR, // AWSS decrypt passwd error
AWSS_GOT_SSID_PASSWD, // AWSS parse ssid and passwd successfully
AWSS_CONNECT_ADHA, // AWSS try to connnect adha (device discover, router solution)
AWSS_CONNECT_ADHA_FAIL, // AWSS fails to connect adha
AWSS_CONNECT_AHA, // AWSS try to connect aha (AP solution)
AWSS_CONNECT_AHA_FAIL, // AWSS fails to connect aha
AWSS_SETUP_NOTIFY, // AWSS sends out device setup information (AP and router solution)
AWSS_CONNECT_ROUTER, // AWSS try to connect destination router
AWSS_CONNECT_ROUTER_FAIL, // AWSS fails to connect destination router.
AWSS_GOT_IP, // AWSS connects destination successfully and got ip address
AWSS_SUC_NOTIFY, // AWSS sends out success notify (AWSS sucess)
AWSS_BIND_NOTIFY, // AWSS sends out bind notify information to support bind between user and device
AWSS_ENABLE_TIMEOUT, // AWSS enable timeout(user needs to call awss_config_press again to enable awss)
AWSS_RESET = 0x3000, // Linkkit reset success (just got reset response from cloud without any other operation)
};
#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
}
#endif
#endif
2.app中对配网的调用:
/*
* application_start is application entrance based on AliOS Things.
*/
int application_start(int argc, char **argv)
{
......
/*
* set device triple ID information before AWSS, otherwise AWSS will fail.
* HAL_SetProductKey(product_key);
* HAL_SetProductSecret(product_secret);
* HAL_SetDeviceName(dev_name);
* HAL_SetDeviceSecret(dev_secret);
*/
set_iotx_info();
/*
* set log level to print debug information about AWSS
*/
LITE_set_loglevel(5); // 5 for debug level
/*
* Start netmgr task for AWSS
* default stack size of netmgr task is 4096B,
* if the module or die takes more stack size,
* please set larger stack size (maybe, 6KB)
*/
#ifdef SUPPORT_DEV_AP
aos_task_new("dap_open", awss_open_dev_ap, NULL, 4096);
#else
aos_task_new("netmgr_start", start_netmgr, NULL, 4096);
#endif
aos_loop_run();
return 0;
}
#ifdef SUPPORT_DEV_AP
void awss_open_dev_ap(void *p)
{
iotx_event_regist_cb(linkkit_event_monitor);
LOG("%s\n", __func__);
if (netmgr_start(false) != 0) {
aos_msleep(2000);
awss_dev_ap_start();
}
aos_task_exit(0);
}
#endif
static void start_netmgr(void *p)
{
/*
* register event callback to detect event of AWSS
*/
iotx_event_regist_cb(linkkit_event_monitor);
netmgr_start(true);
aos_task_exit(0);
}
Note:
[x] set_iotx_info一定要在awss_start或netmgr_start之前调用来设备设备三元组信息,否则的话设备无法解析路由器的PASSWORD,PASSWORD采用加密措施保证安全性,而密钥需要借助于三元组信息计算;
[x] LIET_set_loglevel,如果需要调试打开调试log,该函数需要在awss_start前调用;
[x] 另外,awss_start只是开始AWSS服务(发现周围的AP列表),并未使能AWSS服务,如果需要设备解析配 网包,还需要调用awss_press_config来使能AWSS(设备热点配网除外),这么设计主要考虑安全性,确保用户可以触达设备;
[x] 调用awss_press_config的时机和策略,虽然Demo中采用按键触发,但产品厂商可以根据自己的产品的特定来自行设计;
目前awss_start已经被AliOS封装在netmgr模块中(netmgr_start),具体可以阅读netmgr_start的代码:
int netmgr_start(bool autoconfig)
{
......
/*
* if the last the ap information is exist
* try to connect the last AP.
*/
if (has_valid_ap() == 1) {
aos_post_event(EV_WIFI, CODE_WIFI_CMD_RECONNECT, 0);
return 0;
}
......
/*
* if the last the ap information is not exist
* start AWSS (Alibaba Wireless Setup Service)
*/
if (autoconfig) {
netmgr_wifi_config_start(); // call awss_start()
return 0;
}
......
return -1;
}
3.特定Demo说明:
- 从设备热点配网切换到其他配网模式,调用do_awss:
void do_awss()
{
aos_task_new("dap_close", awss_close_dev_ap, NULL, 2048);
aos_task_new("netmgr_start", start_netmgr, NULL, 4096);
}
static void awss_close_dev_ap(void *p)
{
awss_dev_ap_stop();
LOG("%s exit\n", __func__);
aos_task_exit(0);
}
static void start_netmgr(void *p)
{
iotx_event_regist_cb(linkkit_event_monitor);
LOG("%s\n", __func__);
aos_msleep(2000);
netmgr_start(true);
aos_task_exit(0);
}
- 从其他配网模式切换到设备热点配网,调用do_awss_dev_ap:
void do_awss_dev_ap()
{
aos_task_new("netmgr_stop", stop_netmgr, NULL, 4096);
aos_task_new("dap_open", awss_open_dev_ap, NULL, 4096);
}
static void stop_netmgr(void *p)
{
awss_stop();
LOG("%s\n", __func__);
aos_task_exit(0);
}
static void awss_open_dev_ap(void *p)
{
iotx_event_regist_cb(linkkit_event_monitor);
LOG("%s\n", __func__);
if (netmgr_start(false) != 0) {
aos_msleep(2000);
awss_dev_ap_start();
}
aos_task_exit(0);
}
更多的WiFi配网的描述可参见配网开发文档。