ESP8266 RTOS SDK学习之 SmartConfig智能配网

写在前面: 

本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。

SmartConfig是什么?就是人们常说一键智能配网,通常用的最多的就是我们用手机去连 WiFi,而 8266 SDK开发上也有智能配网这个功能,那么,它是怎么实现的呢?首先我们需要了解在 8266中有两种智能配网方式,一个是用 ESPTouch,另一个是用AirKiss(飞吻),在开发中是可以两种同时使用的,然后下面我们来分析一下代码吧!

 

/******************************************************************************
 * FunctionName : smartconfig_task
 * Description  : smartconfig任务
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR smartconfig_task(void *pvParameters)
{
	wifi_station_disconnect();			// 先关闭连接
	os_printf("\n>>>>>>>>>> enter smartconfig mode\n");

//	os_timer_disarm(&WifiLED_250ms);
//	os_timer_setfn(&WifiLED_250ms, (os_timer_func_t *)wifiled_state_cb, NULL);
//	os_timer_arm(&WifiLED_250ms, 250, 1);

	smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS);	// 设置快连模式类型(ESPTOUCH和AIRKISS同时使用),必须在 smartconfig_start之前调用
	smartconfig_start(smartconfig_done);

	os_printf("\n>>>>>>>>>> smartconfig distribution network wait.....\n");
	while(1)
	{
		if (wifi_station_get_connect_status() == STATION_GOT_IP)	// 等待连接到 AP
		{
//			GLED_ON();
			break;
		}
		vTaskDelay(200 / portTICK_RATE_MS);
	}

	os_printf("\n>>>>>>>>>> esp8266 distribution network success\n\n");
	vTaskDelete(NULL);
}

简单说下上面的流程:首先,额,先关闭 WiFi的连接状态(不管有没有连,因为不知道在开机的时候有没有自动连上,连上了就没必要进行这个配网了,除非你想换个 WiFi连接,额这个不深究了);然后配置它的模式,有三种(选择你需要的),在程序里面自己可以定位去看看;最后不用说了,一直等待,直到连接完成,然后状态什么的,可以在串口打印数据里面可以观察,当然,你一可以添加物理上的指示,例如我注释掉的那些 LED对应状态的代码;值得注意的是 smartconfig_start(smartconfig_done); 这个式子里面,我们要配置 smartconfig_done函数,这个函数是用来分析在连接过程中所处的状态,代码如下

/******************************************************************************
 * FunctionName : smartconfig_done
 * Description  : smartconfig 状态发生改变时,进入该函数
 * Parameters   : status
 * 				  pdata
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR smartconfig_done(sc_status status, void *pdata)
{
    switch(status) {
    	/* 连接未开始,请勿在此阶段开始连接 */
        case SC_STATUS_WAIT:
            printf("SC_STATUS_WAIT\n");
            break;

        /* 发现信道,请在此阶段开启 APP进行配对 */
        case SC_STATUS_FIND_CHANNEL:
            printf("SC_STATUS_FIND_CHANNEL\n");
            break;

        /* 获取到 Wi-Fi名称和密码 */
        case SC_STATUS_GETTING_SSID_PSWD:
            printf("SC_STATUS_GETTING_SSID_PSWD\n");
            sc_type *type = pdata;
            /* 判断类型,在这一步发来的数据 pdata中应该有配置类型 */
            if (*type == SC_TYPE_ESPTOUCH) {
                printf("SC_TYPE:SC_TYPE_ESPTOUCH\n");
            } else {
                printf("SC_TYPE:SC_TYPE_AIRKISS\n");
            }
            break;

        /* 开始连接 Wi-Fi */
        case SC_STATUS_LINK:
            printf("SC_STATUS_LINK\n");
            struct station_config *sta_conf = pdata;

            wifi_station_set_config(sta_conf);		// 设置配置并保存到 flash
            wifi_station_disconnect();
            wifi_station_connect();
            break;

        /* 获取到IP,连接路由完成 */
        case SC_STATUS_LINK_OVER:
            printf("SC_STATUS_LINK_OVER\n");
            /* 如果使用的是 SmartConfig,此时手机会将自己的 IP地址发给ESP8266 */
            if (pdata != NULL) {
                //SC_TYPE_ESPTOUCH
                uint8 phone_ip[4] = {0};

                memcpy(phone_ip, (uint8*)pdata, 4);
                printf("Phone ip: %d.%d.%d.%d\n",phone_ip[0],phone_ip[1],phone_ip[2],phone_ip[3]);
            }
            /* 如果是使用的 Airkiss方式,到这一步还没有完成,还会跟微信进行数据交互,应该告知微信配网完成之类的 */
            else {
                //SC_TYPE_AIRKISS - support airkiss v2.0
                airkiss_start_discover();	// 开始 Airkiss内网发现
            }
            smartconfig_stop();				// SmartConfig 完成,停止配置
            break;
    }

}

好了,到这里,如果是用 ESPTOUCH进行连接的话,基本没问题了,若是用 Airkiss的话,还需要以下这些代码(即调用 airkiss_start_discover(void) 函数)

/******************************************************************************
 * FunctionName : airkiss_start_discover
 * Description  : airkiss内网发现
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR airkiss_start_discover(void)
{
	ssdp_udp.local_port = DEFAULT_LAN_PORT;		// 设置本地端口
	pssdpudpconn.type = ESPCONN_UDP;			// 设置通信方式为 UDP
	pssdpudpconn.proto.udp = &(ssdp_udp);
	espconn_regist_recvcb(&pssdpudpconn, airkiss_wifilan_recv_callback);	// 注册收到数据回调函数
	espconn_create(&pssdpudpconn);				// 创建一个UDP传输

	os_timer_disarm(&ssdp_time_serv);
	os_timer_setfn(&ssdp_time_serv, (os_timer_func_t *)airkiss_wifilan_time_callback, NULL);	//注册airkiss定时回调函数
	os_timer_arm(&ssdp_time_serv, 1000, 1);		// 1s
}

然后,这里有个注册回调函数和定时回调函数需要处理

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "espressif/espconn.h"
#include "espressif/airkiss.h"


#define DEVICE_TYPE 		"gh_9e2cff3dfa51" //wechat public number
#define DEVICE_ID 			"122475" //model ID

#define DEFAULT_LAN_PORT 	12476

LOCAL esp_udp ssdp_udp;
LOCAL struct espconn pssdpudpconn;
LOCAL os_timer_t ssdp_time_serv;

uint8  lan_buf[200];
uint16 lan_buf_len;
uint8  udp_sent_cnt = 0;


/*===================================
 *  Smartconfig Airkiss FUNCTIONS   *
====================================*/

const airkiss_config_t akconf =
{
	(airkiss_memset_fn)&memset,
	(airkiss_memcpy_fn)&memcpy,
	(airkiss_memcmp_fn)&memcmp,
	0,
};

/******************************************************************************
 * FunctionName : airkiss_wifilan_time_callback
 * Description  : airkiss定时回调
 * Parameters   : arg
 * 				  pdata
 * 				  len
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR airkiss_wifilan_time_callback(void)
{
	uint16 i;
	airkiss_lan_ret_t ret;

	/* airkiss_wifilan_time_callback运行三十次后停止运行 */
	if ((udp_sent_cnt++) >30) {
		udp_sent_cnt = 0;
		os_timer_disarm(&ssdp_time_serv);//s
		//return;
	}

	/* 设置本地udp发送端口号,IP地址设置成255.255.255.255是进行广播,UDP有单播,多播和广播三种模式 */
	ssdp_udp.remote_port = DEFAULT_LAN_PORT;
	ssdp_udp.remote_ip[0] = 255;
	ssdp_udp.remote_ip[1] = 255;
	ssdp_udp.remote_ip[2] = 255;
	ssdp_udp.remote_ip[3] = 255;
	lan_buf_len = sizeof(lan_buf);
	ret = airkiss_lan_pack(AIRKISS_LAN_SSDP_NOTIFY_CMD,
		DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf);
	if (ret != AIRKISS_LAN_PAKE_READY) {
		os_printf("Pack lan packet error!");
		return;
	}

	ret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len);
	if (ret != 0) {
		os_printf("UDP send error!");
	}
	os_printf("Finish send notify!\n");		// UDP发送完成
}

/******************************************************************************
 * FunctionName : airkiss_wifilan_recv_callback
 * Description  : airkiss无线局域网接收回调
 * Parameters   : arg
 * 				  pdata
 * 				  len
 * Returns      : none
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR airkiss_wifilan_recv_callback(void *arg, char *pdata, unsigned short len)
{
	uint16 i;
	remot_info* pcon_info = NULL;

	airkiss_lan_ret_t ret = airkiss_lan_recv(pdata, len, &akconf);
	airkiss_lan_ret_t packret;

	switch (ret){
	case AIRKISS_LAN_SSDP_REQ:
		espconn_get_connection_info(&pssdpudpconn, &pcon_info, 0);
		os_printf("remote ip: %d.%d.%d.%d \r\n",pcon_info->remote_ip[0],pcon_info->remote_ip[1],
			                                    pcon_info->remote_ip[2],pcon_info->remote_ip[3]);
		os_printf("remote port: %d \r\n",pcon_info->remote_port);

		pssdpudpconn.proto.udp->remote_port = pcon_info->remote_port;
		memcpy(pssdpudpconn.proto.udp->remote_ip,pcon_info->remote_ip,4);
		ssdp_udp.remote_port = DEFAULT_LAN_PORT;

		lan_buf_len = sizeof(lan_buf);
		packret = airkiss_lan_pack(AIRKISS_LAN_SSDP_RESP_CMD,
			DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf);

		if (packret != AIRKISS_LAN_PAKE_READY) {
			os_printf("Pack lan packet error!");
			return;
		}

		os_printf("\r\n\r\n");
		for (i=0; i<lan_buf_len; i++)
			os_printf("%c",lan_buf[i]);
		os_printf("\r\n\r\n");

		packret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len);
		if (packret != 0) {
			os_printf("LAN UDP Send err!");
		}

		break;
	default:
		os_printf("Pack is not ssdq req!%d\r\n",ret);
		break;
	}
}

最后把代码从下往上添加就可以了

嗯嗯,到这里,一个完整的 SmartConfig配置程序就分析完了,最后说下要注意的是,如果使用 Airkiss 进行配网,那么DEVICE_TYPE跟 DEVICE_ID这两个宏要根据你要用的微信公众号所提供的信息去填写,具体看一下官方的解释及使用(戳这里);接着,还得注意的是,这次我们是不是用了 SmartConfig所提供的库,那么,嘿嘿,知道怎么做了吧,在 Makefile里要添加进去哦,不懂的前面的篇章

噢,忘了给出 ESP-TOUCH的资料了

  1. ESP-TOUCH使用指南
  2. 安卓版App代码
  3. IOS版
发布了31 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42992084/article/details/102890854