ESP8266 NonOS-SDK Web配网

ESP8266 NonOS-SDK Web配网

  • 一、原理
  • 二、程序解析
    • 1、初始化 WebServer
    • 2、初始化 SoftAP
    • 3、绑定回调函数
    • 4、数据接收回调函数
    • 5、获取网页传过来的 WiFi 账号和密码
    • 6、数据保存和检查函数
    • 7、解析网页函数
    • 8、服务端写数据函数
    • 9、网页数据
    • 10、完整代码
    • 11、实现方式
  • 三、效果展示
    • 1、连接 WiFi
    • 2、配网首页
    • 3、配网页面
    • 4、配网完成页面

参考博客:[网络篇]ESP8266-SDK教程(六)之网页配置Wi-Fi名称和密码

一、原理

        ESP8266 设置为 STATION + AP 模式。
        STATION 模式又叫做站点工作模式,类似于无线终端,处于 STATION 模式下的 ESP8266,可以连接到 AP。通过 STATION (简称为“STA”)模式,ESP8266 作为客户端连接到路由的 Wi-Fi 信号。
        AP 就是 Access Point 接入点。由 ESP8266 自己开启热点,供别的设备接入,组成一个局域网。

        流程就是这个样子,手机 / 电脑连接 ESP8266 开启的热点,在浏览器打开配网网页,通过网页发送 SSID 和 PWD 给 ESP8266,ESP8266 解析以后得到 SSID 和 PWD 去连接 Wi-Fi。

        我们需要将这个写好的网页,保存到 ESP8266 当中,当 ESP8266 收到 http 请求时,我们再将这个网页发送给浏览器,此时 ESP8266 就是一个很小的 Web Server,处理来自浏览器的 http 请求,然后按照一定格式返回具体的网页,或者其他数据,这些都是通过 TCP 传输的。

二、程序解析

程序我们可以通过 NonOS-SDK 自带的 WebServer 进行改动。

1、初始化 WebServer

//初始化webserver,webserver端口为80,可以通过初始化时传入
void ICACHE_FLASH_ATTR
www_webserver_init(uint32 port) {
     
	LOCAL struct espconn esp_conn;
	LOCAL esp_tcp esptcp;

	esp_conn.type = ESPCONN_TCP;
	esp_conn.state = ESPCONN_NONE;
	esp_conn.proto.tcp = &esptcp;
	esp_conn.proto.tcp->local_port = port;
	espconn_regist_connectcb(&esp_conn, www_webserver_listen);
	espconn_accept(&esp_conn);
}

2、初始化 SoftAP

/*
 * softAP模式初始化代码
 */
void ICACHE_FLASH_ATTR
www_softAP_init(void){
     
	struct softap_config soft_ap_Config;

	//wifi_set_opmode_current(SOFTAP_MODE);//设置为AP模式,不保存到flash
	wifi_set_opmode(STATIONAP_MODE);//设置为STATION+AP模式,并保存到flash

	os_memset(&soft_ap_Config, 0, sizeof(struct softap_config)); // AP参数结构体 = 0

	soft_ap_Config.ssid_len = os_strlen(AP_NAME);//热点名称长度,与你实际的名称长度一致就好
	os_strcpy(soft_ap_Config.ssid, AP_NAME);//实际热点名称设置,可以根据你的需要来
	os_strcpy(soft_ap_Config.password, AP_PWD);//热点密码设置
	soft_ap_Config.authmode = AUTH_OPEN;//若是你的密码为空,加密模式为AUTH_WPA2_PSK,那么ESP8266不会使用你设置的WIFI名称,而是系统生成,因此没有密码就把加密模式改成AUTH_OPEN
	soft_ap_Config.beacon_interval = 100;//信标间隔,默认为100
	soft_ap_Config.channel = 1;//信道,共支持1~13个信道
	soft_ap_Config.max_connection = 4;//最大连接数量,最大支持四个,默认四个
	soft_ap_Config.ssid_hidden = 0;//隐藏SSID,0:不隐藏  1:隐藏
	//wifi_softap_set_config_current(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,不保存到 Flash
	wifi_softap_set_config(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,保存到 Flash
}

3、绑定回调函数

//断开重连回调函数
LOCAL ICACHE_FLASH_ATTR
void www_webserver_recon(void *arg, sint8 err)
{
     
    struct espconn *pesp_conn = arg;

    os_printf("webserver's %d.%d.%d.%d:%d err %d reconnect\n", pesp_conn->proto.tcp->remote_ip[0],
    		pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2],
    		pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port, err);
}

//断开连接回调函数
LOCAL ICACHE_FLASH_ATTR
void www_webserver_discon(void *arg)
{
     
    struct espconn *pesp_conn = arg;

    os_printf("webserver's %d.%d.%d.%d:%d disconnect\n", pesp_conn->proto.tcp->remote_ip[0],
        		pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2],
        		pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port);
}


//绑定回调函数
LOCAL void ICACHE_FLASH_ATTR
www_webserver_listen(void *arg) {
     
	struct espconn *pesp_conn = arg;

	espconn_regist_recvcb(pesp_conn, www_webserver_recv);//数据接收回调函数
	espconn_regist_reconcb(pesp_conn, www_webserver_recon);//断开重连回调函数
	espconn_regist_disconcb(pesp_conn, www_webserver_discon);//断开连接回调函数
}

4、数据接收回调函数

//数据接收回调函数
LOCAL void ICACHE_FLASH_ATTR
www_webserver_recv(void *arg, char *pusrdata, unsigned short length) {
     
	URL_Frame *pURL_Frame = NULL;
	char *pParseBuffer = NULL;
	bool parse_flag = false;
	struct espconn *ptrespconn = arg;
	uint8 sta;

	os_printf("len:%u\n", length);
	if (www_check_data(pusrdata, length) == false) {
     
		os_printf("goto\n");
		goto _temp_exit;
	}

	parse_flag = www_save_data(pusrdata, length);
	if (parse_flag == false) {
     
		www_response_send(ptrespconn, false);
	}


	//os_printf(buffer);
	pURL_Frame = (URL_Frame *) os_zalloc(sizeof(URL_Frame));
	www_parse_url(buffer, pURL_Frame);

	//os_printf("recv:%s\n", pusrdata);
	os_printf("\r\nType[%d]\r\n", pURL_Frame->Type);
	os_printf("pSelect[%s]\r\n", pURL_Frame->pSelect);
	os_printf("pCommand[%s]\r\n", pURL_Frame->pCommand);
	os_printf("pFilename[%s]\r\n", pURL_Frame->pFilename);

	switch (pURL_Frame->Type) {
     
		case GET:
			os_printf("We have a GET request.\n");
			os_printf("pURL_Frame->pFilename: %s\n",pURL_Frame->pFilename);

			sta = wifi_station_get_connect_status();

			os_printf("wifi_station_get_connect_status: %d\n", sta);

			if(pURL_Frame->pFilename[0] == 0){
     
				www_data_send(ptrespconn, true, page_html);
			}
			if(strncmp(pURL_Frame->pFilename, "WebConfig.html", strlen("WebConfig.html")) == 0){
     
				www_data_send(ptrespconn, true, config_html);
			}

			break;

		case POST:
			os_printf("We have a POST request.\n");
			pParseBuffer = (char *)os_strstr(buffer, "\r\n\r\n");

			sta = wifi_station_get_connect_status();
			os_printf("wifi_station_get_connect_status: %d\n", sta);

			if(sta == STATION_GOT_IP){
     
				//www_data_send(ptrespconn, true, "Connect Success!");
				www_data_send(ptrespconn, true, finish_html);
			}
			else if(sta == STATION_WRONG_PASSWORD){
     
				//www_data_send(ptrespconn, true, "Wrong Password!");
				www_data_send(ptrespconn, true, finish_html);
			}
			else{
     
				www_data_send(ptrespconn, true, config_html);
			}

			if(strncmp(pURL_Frame->pCommand, "connect-wifi", strlen("connect-wifi")) == 0){
     
				webconfig_get_wifi_ssid_pwd(pusrdata);
			}


			if (pParseBuffer == NULL) {
     
			     break;

			}

			os_printf("%s\r\n", pParseBuffer);

			break;
	}

	if (buffer != NULL) {
     
		os_free(buffer);
		buffer = NULL;
	}
	os_free(pURL_Frame);
	pURL_Frame = NULL;
	_temp_exit: ;
}

5、获取网页传过来的 WiFi 账号和密码

/* 功  能:将str字符串中的oldstr字符串替换为newstr字符串
 * 参  数:str:操作目标 oldstr:被替换者 newstr:替换者
 * 返回值:返回替换之后的字符串
 * 版  本: V0.2
 */
static char * ICACHE_FLASH_ATTR
strrpc(char *str, char *oldstr, char *newstr){
     
    char bstr[os_strlen(str)];//转换缓冲区
    int len = os_strlen(str);
    int i, len2 = 0;
    
    os_memset(bstr, 0, sizeof(bstr));

    for(i = 0; i < len; i++){
     
        if(!os_strncmp(str + i, oldstr, os_strlen(oldstr))){
     //查找目标字符串
        	strcat(bstr, newstr);
        	len2 = os_strlen(oldstr);
            i += len2 - 1;
        }else{
     
        	strncat(bstr, str + i, 1);//保存一字节进缓冲区
	    }
    }

    os_strcpy(str,bstr);
    return str;
}

//获取网页传过来的 WiFi 账号和密码
static void ICACHE_FLASH_ATTR
webconfig_get_wifi_ssid_pwd(char* urlparam)
{
     
    char *p = NULL, *q = NULL;
    char ssid[32], pass[64];

    os_memset(ssid, 0, sizeof(ssid));
    os_memset(pass, 0, sizeof(pass));

    p = (char *)os_strstr(urlparam, "SSID=");
    q = (char *)os_strstr(urlparam, "PASSWORD=");
    if ( p == NULL || q == NULL ){
     
        return;
    }
    os_memcpy(ssid, p + 5, q - p - 6);
    os_memcpy(pass, q + 9, os_strlen(urlparam) - (q - urlparam) - 9);

    //空格在url参数会转码成+号,+号转码成%2B
    strrpc(ssid, "+", " ");

    os_printf("ssid[%s], pass[%s]\r\n", ssid, pass);

    wifi_set_opmode(STATIONAP_MODE);
    struct station_config stConf;
    stConf.bssid_set = 0;
    os_memset(&stConf.ssid, 0, sizeof(stConf.ssid));
    os_memset(&stConf.password, 0, sizeof(stConf.password));

    os_memcpy(&stConf.ssid, ssid, os_strlen(ssid));
    os_memcpy(&stConf.password, pass, os_strlen(pass));

    wifi_station_set_config(&stConf);

    //重启
    system_restart();
}

6、数据保存和检查函数

LOCAL char *buffer;
static uint32 sumlength = 0;

LOCAL bool ICACHE_FLASH_ATTR
www_save_data(char *precv, uint16 length)
{
     
    bool flag = false;
    char length_buf[10] = {
     0};
    char *ptemp = NULL;
    char *pdata = NULL;
    uint16 headlength = 0;
    static uint32 totallength = 0;

    ptemp = (char *)os_strstr(precv, "\r\n\r\n");

    if (ptemp != NULL) {
     
        length -= ptemp - precv;
        length -= 4;
        totallength += length;
        headlength = ptemp - precv + 4;
        pdata = (char *)os_strstr(precv, "Content-Length: ");

        if (pdata != NULL) {
     
            pdata += 16;
            buffer = (char *)os_strstr(pdata, "\r\n");

            if (buffer != NULL) {
     
                os_memcpy(length_buf, pdata, buffer - pdata);
                sumlength = atoi(length_buf);
            }
        } else {
     
        	if (totallength != 0x00){
     
        		totallength = 0;
        		sumlength = 0;
        		return false;
        	}
        }
        if ((sumlength + headlength) >= 1024) {
     
        	buffer = (char *)os_zalloc(headlength + 1);
            os_memcpy(buffer, precv, headlength + 1);
        } else {
     
        	buffer = (char *)os_zalloc(sumlength + headlength + 1);
        	os_memcpy(buffer, precv, os_strlen(precv));
        }
    } else {
     
        if (buffer != NULL) {
     
            totallength += length;
            os_memcpy(buffer + os_strlen(buffer), precv, length);
        } else {
     
            totallength = 0;
            sumlength = 0;
            return false;
        }
    }

    if (totallength == sumlength) {
     
        totallength = 0;
        sumlength = 0;
        return true;
    } else {
     
        return false;
    }
}

LOCAL bool ICACHE_FLASH_ATTR
www_check_data(char *precv, uint16 length)
{
     
        //bool flag = true;
    char length_buf[10] = {
     0};
    char *ptemp = NULL;
    char *pdata = NULL;
    char *tmp_precvbuffer;
    uint16 tmp_length = length;
    uint32 tmp_totallength = 0;

    ptemp = (char *)os_strstr(precv, "\r\n\r\n");

    if (ptemp != NULL) {
     
        tmp_length -= ptemp - precv;
        tmp_length -= 4;
        tmp_totallength += tmp_length;

        pdata = (char *)os_strstr(precv, "Content-Length: ");

        if (pdata != NULL){
     
            pdata += 16;
            tmp_precvbuffer = (char *)os_strstr(pdata, "\r\n");

            if (tmp_precvbuffer != NULL){
     
                os_memcpy(length_buf, pdata, tmp_precvbuffer - pdata);
                sumlength = atoi(length_buf);
                os_printf("A_dat:%u,tot:%u,lenght:%u\n",sumlength,tmp_totallength,tmp_length);
                if(sumlength != tmp_totallength){
     
                    return false;
                }
            }
        }
    }
    return true;
}

7、解析网页函数

LOCAL void ICACHE_FLASH_ATTR
www_parse_url(char *precv, URL_Frame *purl_frame)
{
     
    char *str = NULL;
    uint8 length = 0;
    char *pbuffer = NULL;
    char *pbufer = NULL;

    if (purl_frame == NULL || precv == NULL) {
     
        return;
    }

    pbuffer = (char *)os_strstr(precv, "Host:");

    if (pbuffer != NULL) {
     
        length = pbuffer - precv;
        pbufer = (char *)os_zalloc(length + 1);
        pbuffer = pbufer;
        os_memcpy(pbuffer, precv, length);
        os_memset(purl_frame->pSelect, 0, URLSize);
        os_memset(purl_frame->pCommand, 0, URLSize);
        os_memset(purl_frame->pFilename, 0, URLSize);

        if (os_strncmp(pbuffer, "GET ", 4) == 0) {
     
            purl_frame->Type = GET;
            pbuffer += 4;
        } else if (os_strncmp(pbuffer, "POST ", 5) == 0) {
     
            purl_frame->Type = POST;
            pbuffer += 5;
        }

        pbuffer ++;
        str = (char *)os_strstr(pbuffer, "HTTP");

        if (str != NULL) {
     
            length = str - pbuffer - 1;
            os_memcpy(purl_frame->pFilename, pbuffer, length);
        }

        os_free(pbufer);
    } else {
     
        return;
    }

    pbuffer = (char *)os_strstr(precv, "SSID");
    if (pbuffer != NULL) {
     
        purl_frame->Type = POST;
        os_memcpy(purl_frame->pCommand, "connect-wifi", strlen("connect-wifi"));
        os_free(pbufer);
    }
}

8、服务端写数据函数

//发送html网页数据
LOCAL void ICACHE_FLASH_ATTR
www_data_send(void *arg, bool responseOK, char *psend)
{
     
    uint16 length = 0;
    char *pbuf = NULL;
    char httphead[256];
    struct espconn *ptrespconn = arg;
    os_memset(httphead, 0, 256);

    if (responseOK) {
     
        os_sprintf(httphead,
                   "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nServer: lwIP/1.4.0\r\n",
                   psend ? os_strlen(psend) : 0);

        if (psend) {
     
            os_sprintf(httphead + os_strlen(httphead),
                       "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n");
            length = os_strlen(httphead) + os_strlen(psend);
            pbuf = (char *)os_zalloc(length + 1);
            os_memcpy(pbuf, httphead, os_strlen(httphead));
            os_memcpy(pbuf + os_strlen(httphead), psend, os_strlen(psend));
        } else {
     
            os_sprintf(httphead + os_strlen(httphead), "\n");
            length = os_strlen(httphead);
        }
    } else {
     
        os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\n\
Content-Length: 0\r\nServer: lwIP/1.4.0\r\n\n");
        length = os_strlen(httphead);
    }

    if (psend) {
     
#ifdef SERVER_SSL_ENABLE
        espconn_secure_sent(ptrespconn, pbuf, length);
#else
        espconn_sent(ptrespconn, pbuf, length);
#endif
    } else {
     
#ifdef SERVER_SSL_ENABLE
        espconn_secure_sent(ptrespconn, httphead, length);
#else
        espconn_sent(ptrespconn, httphead, length);
#endif
    }

    if (pbuf) {
     
        os_free(pbuf);
        pbuf = NULL;
    }
}

//发送json数据
LOCAL void ICACHE_FLASH_ATTR
www_data_send_json(void *arg, bool responseOK, char *psend)
{
     
    uint16 length = 0;
    char *pbuf = NULL;
    char httphead[256];
    struct espconn *ptrespconn = arg;
    os_memset(httphead, 0, 256);

    if (responseOK) {
     
        os_sprintf(httphead,
                   "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nServer: lwIP/1.4.0\r\n",
                   psend ? os_strlen(psend) : 0);

        if (psend) {
     
            os_sprintf(httphead + os_strlen(httphead),
                       "Content-type: application/json\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n");
            length = os_strlen(httphead) + os_strlen(psend);
            pbuf = (char *)os_zalloc(length + 1);
            os_memcpy(pbuf, httphead, os_strlen(httphead));
            os_memcpy(pbuf + os_strlen(httphead), psend, os_strlen(psend));
        } else {
     
            os_sprintf(httphead + os_strlen(httphead), "\n");
            length = os_strlen(httphead);
        }
    } else {
     
        os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\n\
Content-Length: 0\r\nServer: lwIP/1.4.0\r\n\n");
        length = os_strlen(httphead);
    }

    if (psend) {
     
#ifdef SERVER_SSL_ENABLE
        espconn_secure_sent(ptrespconn, pbuf, length);
#else
        espconn_sent(ptrespconn, pbuf, length);
#endif
    } else {
     
#ifdef SERVER_SSL_ENABLE
        espconn_secure_sent(ptrespconn, httphead, length);
#else
        espconn_sent(ptrespconn, httphead, length);
#endif
    }

    if (pbuf) {
     
        os_free(pbuf);
        pbuf = NULL;
    }
}

//发送响应成功数据
LOCAL void ICACHE_FLASH_ATTR
www_response_send(void *arg, bool responseOK)
{
     
    struct espconn *ptrespconn = arg;

    www_data_send(ptrespconn, responseOK, NULL);
}

9、网页数据

不知道为啥,meta 标签里我都设置为 utf-8 了,中文输出还是乱码,所以网页里用的全部都是英文。

//欢迎页面代码
char* page_html = "\r\n"
		"\r\n"
		"    \r\n"
		"        \r\n"
		"        \r\n"</span>
		<span class="token string">"            ZCM IOT WiFi Config\r\n"</span>
		<span class="token string">"        \r\n"
		"    \r\n"
		"    \r\n"
		"        


\r\n" " \r\n" " ZCM IOT WiFi Config\r\n" " \r\n" "
\r\n"
" \r\n" " E-mail: [email protected]\r\n" " \r\n" "
\r\n"
"
\r\n"
" \r\n" " \r\n" " \r\n" "
\r\n"
"
\r\n"
" \r\n" ""; //配网页面 char* config_html = "\r\n" "\r\n" " \r\n" " \r\n" " \r\n"</span> <span class="token string">" ZCM IOT WiFi Config\r\n"</span> <span class="token string">" \r\n" " \r\n" " \r\n" "
\r\n" "

\r\n"
" \r\n" " ZCM IOT WiFi Config\r\n" " \r\n" "
\r\n"
" \r\n" " E-mail: [email protected]\r\n" " \r\n" "
\r\n"
"
\r\n"
"
\r\n"
"
\r\n" " \r\n"" \r\n"" \r\n"" \r\n"" \r\n"" \r\n"" \r\n""
\r\n" " Wi-Fi Name:\r\n" " \r\n" "
\r\n" " Wi-Fi    Pwd:\r\n" " \r\n" "
\r\n"
" \r\n" " \r\n"
" \r\n" ""; //配网完成 char* finish_html = "\r\n" "\r\n" " \r\n" " \r\n" " \r\n"</span> <span class="token string">" ZCM IOT WiFi Config\r\n"</span> <span class="token string">" \r\n" " \r\n" " \r\n" "
\r\n" "

\r\n"
" \r\n" " ZCM IOT WiFi Config\r\n" " \r\n" "
\r\n"
" \r\n" " E-mail: [email protected]\r\n" " \r\n" "
\r\n"
"
\r\n"
" \r\n" " Connecting to Wi-Fi, the connection is complete after the LED flashes three times!\r\n" "
\r\n"
" Steady on means the connection failed, please re-enter!\r\n" "

\r\n"
" \r\n" " \r\n" " \r\n" "
\r\n"
" \r\n" " Back Home\r\n" " \r\n" "
\r\n" "
\r\n"
" \r\n" "";

10、完整代码

/*
 * webserver.c
 *
 *  Created on: 2021年4月8日
 *      Author: wxhntmy
 */

#include "espconn.h"
#include "mem.h"
#include "ets_sys.h"
#include "osapi.h"

#include "user_interface.h"

#include "user_devicefind.h"
#include "user_webserver.h"
#include "user_esp_platform.h"
#include "user_tcpclient.h"


#include "webserver.h"	//头文件只声明了几个函数

char* AP_NAME = "zcm_iot_wifi"; //wifi名字
char* AP_PWD = "123456"; //wifi密码

//欢迎页面代码
char* page_html = "\r\n"
		"\r\n"
		"    \r\n"
		"        \r\n"
		"        \r\n"</span>
		<span class="token string">"            ZCM IOT WiFi Config\r\n"</span>
		<span class="token string">"        \r\n"
		"    \r\n"
		"    \r\n"
		"        


\r\n" " \r\n" " ZCM IOT WiFi Config\r\n" " \r\n" "
\r\n"
" \r\n" " E-mail: [email protected]\r\n" " \r\n" "
\r\n"
"
\r\n"
" \r\n" " \r\n" " \r\n" "
\r\n"
"
\r\n"
" \r\n" ""; //配网页面 char* config_html = "\r\n" "\r\n" " \r\n" " \r\n" " \r\n"</span> <span class="token string">" ZCM IOT WiFi Config\r\n"</span> <span class="token string">" \r\n" " \r\n" " \r\n" "
\r\n" "

\r\n"
" \r\n" " ZCM IOT WiFi Config\r\n" " \r\n" "
\r\n"
" \r\n" " E-mail: [email protected]\r\n" " \r\n" "
\r\n"
"
\r\n"
"
\r\n"
"
\r\n" " \r\n"" \r\n"" \r\n"" \r\n"" \r\n"" \r\n"" \r\n""
\r\n" " Wi-Fi Name:\r\n" " \r\n" "
\r\n" " Wi-Fi    Pwd:\r\n" " \r\n" "
\r\n"
" \r\n" " \r\n"
" \r\n" ""; //配网完成 char* finish_html = "\r\n" "\r\n" " \r\n" " \r\n" " \r\n"</span> <span class="token string">" ZCM IOT WiFi Config\r\n"</span> <span class="token string">" \r\n" " \r\n" " \r\n" "
\r\n" "

\r\n"
" \r\n" " ZCM IOT WiFi Config\r\n" " \r\n" "
\r\n"
" \r\n" " E-mail: [email protected]\r\n" " \r\n" "
\r\n"
"
\r\n"
" \r\n" " Connecting to Wi-Fi, the connection is complete after the LED flashes three times!\r\n" "
\r\n"
" Steady on means the connection failed, please re-enter!\r\n" "

\r\n"
" \r\n" " \r\n" " \r\n" "
\r\n"
" \r\n" " Back Home\r\n" " \r\n" "
\r\n" "
\r\n"
" \r\n" ""; LOCAL void ICACHE_FLASH_ATTR www_data_send(void *arg, bool responseOK, char *psend) { uint16 length = 0; char *pbuf = NULL; char httphead[256]; struct espconn *ptrespconn = arg; os_memset(httphead, 0, 256); if (responseOK) { os_sprintf(httphead, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nServer: lwIP/1.4.0\r\n", psend ? os_strlen(psend) : 0); if (psend) { os_sprintf(httphead + os_strlen(httphead), "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n"); length = os_strlen(httphead) + os_strlen(psend); pbuf = (char *)os_zalloc(length + 1); os_memcpy(pbuf, httphead, os_strlen(httphead)); os_memcpy(pbuf + os_strlen(httphead), psend, os_strlen(psend)); } else { os_sprintf(httphead + os_strlen(httphead), "\n"); length = os_strlen(httphead); } } else { os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\n\ Content-Length: 0\r\nServer: lwIP/1.4.0\r\n\n"); length = os_strlen(httphead); } if (psend) { #ifdef SERVER_SSL_ENABLE espconn_secure_sent(ptrespconn, pbuf, length); #else espconn_sent(ptrespconn, pbuf, length); #endif } else { #ifdef SERVER_SSL_ENABLE espconn_secure_sent(ptrespconn, httphead, length); #else espconn_sent(ptrespconn, httphead, length); #endif } if (pbuf) { os_free(pbuf); pbuf = NULL; } } LOCAL void ICACHE_FLASH_ATTR www_data_send_json(void *arg, bool responseOK, char *psend) { uint16 length = 0; char *pbuf = NULL; char httphead[256]; struct espconn *ptrespconn = arg; os_memset(httphead, 0, 256); if (responseOK) { os_sprintf(httphead, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nServer: lwIP/1.4.0\r\n", psend ? os_strlen(psend) : 0); if (psend) { os_sprintf(httphead + os_strlen(httphead), "Content-type: application/json\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n"); length = os_strlen(httphead) + os_strlen(psend); pbuf = (char *)os_zalloc(length + 1); os_memcpy(pbuf, httphead, os_strlen(httphead)); os_memcpy(pbuf + os_strlen(httphead), psend, os_strlen(psend)); } else { os_sprintf(httphead + os_strlen(httphead), "\n"); length = os_strlen(httphead); } } else { os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\n\ Content-Length: 0\r\nServer: lwIP/1.4.0\r\n\n"); length = os_strlen(httphead); } if (psend) { #ifdef SERVER_SSL_ENABLE espconn_secure_sent(ptrespconn, pbuf, length); #else espconn_sent(ptrespconn, pbuf, length); #endif } else { #ifdef SERVER_SSL_ENABLE espconn_secure_sent(ptrespconn, httphead, length); #else espconn_sent(ptrespconn, httphead, length); #endif } if (pbuf) { os_free(pbuf); pbuf = NULL; } } LOCAL void ICACHE_FLASH_ATTR www_response_send(void *arg, bool responseOK) { struct espconn *ptrespconn = arg; www_data_send(ptrespconn, responseOK, NULL); } LOCAL void ICACHE_FLASH_ATTR www_parse_url(char *precv, URL_Frame *purl_frame) { char *str = NULL; uint8 length = 0; char *pbuffer = NULL; char *pbufer = NULL; if (purl_frame == NULL || precv == NULL) { return; } pbuffer = (char *)os_strstr(precv, "Host:"); if (pbuffer != NULL) { length = pbuffer - precv; pbufer = (char *)os_zalloc(length + 1); pbuffer = pbufer; os_memcpy(pbuffer, precv, length); os_memset(purl_frame->pSelect, 0, URLSize); os_memset(purl_frame->pCommand, 0, URLSize); os_memset(purl_frame->pFilename, 0, URLSize); if (os_strncmp(pbuffer, "GET ", 4) == 0) { purl_frame->Type = GET; pbuffer += 4; } else if (os_strncmp(pbuffer, "POST ", 5) == 0) { purl_frame->Type = POST; pbuffer += 5; } pbuffer ++; str = (char *)os_strstr(pbuffer, "HTTP"); if (str != NULL) { length = str - pbuffer - 1; os_memcpy(purl_frame->pFilename, pbuffer, length); } os_free(pbufer); } else { return; } pbuffer = (char *)os_strstr(precv, "SSID"); if (pbuffer != NULL) { purl_frame->Type = POST; os_memcpy(purl_frame->pCommand, "connect-wifi", strlen("connect-wifi")); os_free(pbufer); } } LOCAL char *buffer; static uint32 sumlength = 0; LOCAL bool ICACHE_FLASH_ATTR www_save_data(char *precv, uint16 length) { bool flag = false; char length_buf[10] = { 0}; char *ptemp = NULL; char *pdata = NULL; uint16 headlength = 0; static uint32 totallength = 0; ptemp = (char *)os_strstr(precv, "\r\n\r\n"); if (ptemp != NULL) { length -= ptemp - precv; length -= 4; totallength += length; headlength = ptemp - precv + 4; pdata = (char *)os_strstr(precv, "Content-Length: "); if (pdata != NULL) { pdata += 16; buffer = (char *)os_strstr(pdata, "\r\n"); if (buffer != NULL) { os_memcpy(length_buf, pdata, buffer - pdata); sumlength = atoi(length_buf); } } else { if (totallength != 0x00){ totallength = 0; sumlength = 0; return false; } } if ((sumlength + headlength) >= 1024) { buffer = (char *)os_zalloc(headlength + 1); os_memcpy(buffer, precv, headlength + 1); } else { buffer = (char *)os_zalloc(sumlength + headlength + 1); os_memcpy(buffer, precv, os_strlen(precv)); } } else { if (buffer != NULL) { totallength += length; os_memcpy(buffer + os_strlen(buffer), precv, length); } else { totallength = 0; sumlength = 0; return false; } } if (totallength == sumlength) { totallength = 0; sumlength = 0; return true; } else { return false; } } LOCAL bool ICACHE_FLASH_ATTR www_check_data(char *precv, uint16 length) { //bool flag = true; char length_buf[10] = { 0}; char *ptemp = NULL; char *pdata = NULL; char *tmp_precvbuffer; uint16 tmp_length = length; uint32 tmp_totallength = 0; ptemp = (char *)os_strstr(precv, "\r\n\r\n"); if (ptemp != NULL) { tmp_length -= ptemp - precv; tmp_length -= 4; tmp_totallength += tmp_length; pdata = (char *)os_strstr(precv, "Content-Length: "); if (pdata != NULL){ pdata += 16; tmp_precvbuffer = (char *)os_strstr(pdata, "\r\n"); if (tmp_precvbuffer != NULL){ os_memcpy(length_buf, pdata, tmp_precvbuffer - pdata); sumlength = atoi(length_buf); os_printf("A_dat:%u,tot:%u,lenght:%u\n",sumlength,tmp_totallength,tmp_length); if(sumlength != tmp_totallength){ return false; } } } } return true; } /* 功 能:将str字符串中的oldstr字符串替换为newstr字符串 * 参 数:str:操作目标 oldstr:被替换者 newstr:替换者 * 返回值:返回替换之后的字符串 * 版 本: V0.2 */ static char * ICACHE_FLASH_ATTR strrpc(char *str,char *oldstr,char *newstr){ char bstr[os_strlen(str)];//转换缓冲区 int len = os_strlen(str); int i, len2 = 0; os_memset(bstr, 0, sizeof(bstr)); for(i = 0; i < len; i++){ if(!os_strncmp(str + i, oldstr, os_strlen(oldstr))){ //查找目标字符串 strcat(bstr, newstr); len2 = os_strlen(oldstr); i += len2 - 1; }else{ strncat(bstr, str + i, 1);//保存一字节进缓冲区 } } os_strcpy(str,bstr); return str; } static void ICACHE_FLASH_ATTR webconfig_get_wifi_ssid_pwd(char* urlparam) { char *p = NULL, *q = NULL; char ssid[32], pass[64]; os_memset(ssid, 0, sizeof(ssid)); os_memset(pass, 0, sizeof(pass)); p = (char *)os_strstr(urlparam, "SSID="); q = (char *)os_strstr(urlparam, "PASSWORD="); if ( p == NULL || q == NULL ){ return; } os_memcpy(ssid, p + 5, q - p - 6); os_memcpy(pass, q + 9, os_strlen(urlparam) - (q - urlparam) - 9); //空格在url参数会转码成+号,+号转码成%2B strrpc(ssid, "+", " "); os_printf("ssid[%s], pass[%s]\r\n", ssid, pass); wifi_set_opmode(STATIONAP_MODE); struct station_config stConf; stConf.bssid_set = 0; os_memset(&stConf.ssid, 0, sizeof(stConf.ssid)); os_memset(&stConf.password, 0, sizeof(stConf.password)); os_memcpy(&stConf.ssid, ssid, os_strlen(ssid)); os_memcpy(&stConf.password, pass, os_strlen(pass)); wifi_station_set_config(&stConf); //重启 system_restart(); } LOCAL void ICACHE_FLASH_ATTR www_webserver_recv(void *arg, char *pusrdata, unsigned short length) { URL_Frame *pURL_Frame = NULL; char *pParseBuffer = NULL; bool parse_flag = false; struct espconn *ptrespconn = arg; uint8 sta; os_printf("len:%u\n", length); if (www_check_data(pusrdata, length) == false) { os_printf("goto\n"); goto _temp_exit; } parse_flag = www_save_data(pusrdata, length); if (parse_flag == false) { www_response_send(ptrespconn, false); } //os_printf(buffer); pURL_Frame = (URL_Frame *) os_zalloc(sizeof(URL_Frame)); www_parse_url(buffer, pURL_Frame); //os_printf("recv:%s\n", pusrdata); os_printf("\r\nType[%d]\r\n", pURL_Frame->Type); os_printf("pSelect[%s]\r\n", pURL_Frame->pSelect); os_printf("pCommand[%s]\r\n", pURL_Frame->pCommand); os_printf("pFilename[%s]\r\n", pURL_Frame->pFilename); switch (pURL_Frame->Type) { case GET: os_printf("We have a GET request.\n"); os_printf("pURL_Frame->pFilename: %s\n",pURL_Frame->pFilename); sta = wifi_station_get_connect_status(); if(sta == STATION_GOT_IP){ //www_data_send(ptrespconn, true, "WiFi is connected!"); www_data_send(ptrespconn, true, finish_html); } else{ if(pURL_Frame->pFilename[0] == 0){ www_data_send(ptrespconn, true, page_html); } if(strncmp(pURL_Frame->pFilename, "WebConfig.html", strlen("WebConfig.html")) == 0){ www_data_send(ptrespconn, true, config_html); } } break; case POST: os_printf("We have a POST request.\n"); pParseBuffer = (char *)os_strstr(buffer, "\r\n\r\n"); sta = wifi_station_get_connect_status(); if(sta == STATION_GOT_IP){ //www_data_send(ptrespconn, true, "Connect Success!"); www_data_send(ptrespconn, true, finish_html); } else if(sta == STATION_WRONG_PASSWORD){ //www_data_send(ptrespconn, true, "Wrong Password!"); www_data_send(ptrespconn, true, finish_html); } else{ www_data_send(ptrespconn, true, config_html); } if(strncmp(pURL_Frame->pCommand, "connect-wifi", strlen("connect-wifi")) == 0){ webconfig_get_wifi_ssid_pwd(pusrdata); } if (pParseBuffer == NULL) { break; } os_printf("%s\r\n", pParseBuffer); break; } if (buffer != NULL) { os_free(buffer); buffer = NULL; } os_free(pURL_Frame); pURL_Frame = NULL; _temp_exit: ; } LOCAL ICACHE_FLASH_ATTR void www_webserver_recon(void *arg, sint8 err) { struct espconn *pesp_conn = arg; os_printf("webserver's %d.%d.%d.%d:%d err %d reconnect\n", pesp_conn->proto.tcp->remote_ip[0], pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2], pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port, err); } LOCAL ICACHE_FLASH_ATTR void www_webserver_discon(void *arg) { struct espconn *pesp_conn = arg; os_printf("webserver's %d.%d.%d.%d:%d disconnect\n", pesp_conn->proto.tcp->remote_ip[0], pesp_conn->proto.tcp->remote_ip[1],pesp_conn->proto.tcp->remote_ip[2], pesp_conn->proto.tcp->remote_ip[3],pesp_conn->proto.tcp->remote_port); } //绑定回调函数 LOCAL void ICACHE_FLASH_ATTR www_webserver_listen(void *arg) { struct espconn *pesp_conn = arg; espconn_regist_recvcb(pesp_conn, www_webserver_recv); espconn_regist_reconcb(pesp_conn, www_webserver_recon); espconn_regist_disconcb(pesp_conn, www_webserver_discon); } /* * softAP模式初始化代码 */ void ICACHE_FLASH_ATTR www_softAP_init(void){ struct softap_config soft_ap_Config; //wifi_set_opmode_current(SOFTAP_MODE);//设置为AP模式,不保存到flash wifi_set_opmode(STATIONAP_MODE);//设置为STATION+AP模式,并保存到flash os_memset(&soft_ap_Config, 0, sizeof(struct softap_config)); // AP参数结构体 = 0 soft_ap_Config.ssid_len = os_strlen(AP_NAME);//热点名称长度,与你实际的名称长度一致就好 os_strcpy(soft_ap_Config.ssid, AP_NAME);//实际热点名称设置,可以根据你的需要来 os_strcpy(soft_ap_Config.password, AP_PWD);//热点密码设置 soft_ap_Config.authmode = AUTH_OPEN;//若是你的密码为空,加密模式为AUTH_WPA2_PSK,那么ESP8266不会使用你设置的WIFI名称,而是系统生成,因此没有密码就把加密模式改成AUTH_OPEN soft_ap_Config.beacon_interval = 100;//信标间隔,默认为100 soft_ap_Config.channel = 1;//信道,共支持1~13个信道 soft_ap_Config.max_connection = 4;//最大连接数量,最大支持四个,默认四个 soft_ap_Config.ssid_hidden = 0;//隐藏SSID,0:不隐藏 1:隐藏 //wifi_softap_set_config_current(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,不保存到 Flash wifi_softap_set_config(&soft_ap_Config);//设置 Wi-Fi SoftAP 接口配置,保存到 Flash } //初始化webserver void ICACHE_FLASH_ATTR www_webserver_init(uint32 port) { LOCAL struct espconn esp_conn; LOCAL esp_tcp esptcp; esp_conn.type = ESPCONN_TCP; esp_conn.state = ESPCONN_NONE; esp_conn.proto.tcp = &esptcp; esp_conn.proto.tcp->local_port = port; espconn_regist_connectcb(&esp_conn, www_webserver_listen); espconn_accept(&esp_conn); }

11、实现方式

在主函数中调用以下两个函数即可

//初始化AP模式
www_softAP_init();
//开启webserver
www_webserver_init(SERVER_PORT);

三、效果展示

1、连接 WiFi

ESP8266 NonOS-SDK Web配网_第1张图片

2、配网首页

打开浏览器,地址栏输入 192.168.4.1

ESP8266 NonOS-SDK Web配网_第2张图片

3、配网页面

ESP8266 NonOS-SDK Web配网_第3张图片

4、配网完成页面

ESP8266 NonOS-SDK Web配网_第4张图片

你可能感兴趣的:(ESP8266,wifi)