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模式,不保存到flashwifi_set_opmode(STATIONAP_MODE);//设置为STATION+AP模式,并保存到flashos_memset(&soft_ap_Config, 0, sizeof(struct softap_config)); // AP参数结构体 = 0soft_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_OPENsoft_ap_Config.beacon_interval = 100;//信标间隔,默认为100soft_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 接口配置,不保存到 Flashwifi_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, "<meta charset='UTF-8'>Connect Success!");www_data_send(ptrespconn, true, finish_html);}else if(sta == STATION_WRONG_PASSWORD){//www_data_send(ptrespconn, true, "<meta charset='UTF-8'>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参数会转码成+号,+号转码成%2Bstrrpc(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_ENABLEespconn_secure_sent(ptrespconn, pbuf, length);
#elseespconn_sent(ptrespconn, pbuf, length);
#endif} else {#ifdef SERVER_SSL_ENABLEespconn_secure_sent(ptrespconn, httphead, length);
#elseespconn_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_ENABLEespconn_secure_sent(ptrespconn, pbuf, length);
#elseespconn_sent(ptrespconn, pbuf, length);
#endif} else {#ifdef SERVER_SSL_ENABLEespconn_secure_sent(ptrespconn, httphead, length);
#elseespconn_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 = "<!DOCTYPE html>\r\n""<html>\r\n""    <head>\r\n""        <meta charset=\"utf-8\" content=\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" name=\"viewport\"/>\r\n""        <title>\r\n""            ZCM IOT WiFi Config\r\n""        </title>\r\n""    </head>\r\n""    <body style=\"background: #00F948\">\r\n""        <div align=\"center\"><br/><br/>\r\n""            <font>\r\n""                ZCM IOT WiFi Config\r\n""            </font>\r\n""            <br/>\r\n""            <font>\r\n""                E-mail: wxhntmy@163.com\r\n""            </font>\r\n""            <br/>\r\n""            <br/>\r\n""            <a href=\"WebConfig.html\" text-decoration=\"none\">\r\n""                <button formtarget=\"_self\" style=\"display:block;margin:0 auto\">\r\n""                    Start Config\r\n""                </button>\r\n""            </a>\r\n""           <br/>\r\n""        </div>\r\n""    </body>\r\n""</html>";
//配网页面
char* config_html = "<!DOCTYPE html>\r\n""<html>\r\n""    <head>\r\n""        <meta charset=\"utf-8\" content=\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" name=\"viewport\"/>\r\n""        <title>\r\n""            ZCM IOT WiFi Config\r\n""        </title>\r\n""    </head>\r\n""    <body style=\"background: #00F948\">\r\n""        <div align=\"center\">\r\n""         <br><br>\r\n""            <font>\r\n""                ZCM IOT WiFi Config\r\n""            </font>\r\n""            <br/>\r\n""            <font>\r\n""                E-mail: wxhntmy@163.com\r\n""            </font>\r\n""            <br/>\r\n""            <br/>\r\n""        </div>\r\n""        <form action=\"WiFiConfig.html\" enctype=\"application/x-www-form-urlencoded\" method=\"post\">\r\n""            <table align=\"center\" border=\"0\" cellspacing=\"10\">\r\n""                <tr>\r\n""                    <td>\r\n""                        Wi-Fi Name:\r\n""                        <input name=\"SSID\" placeholder=\"input Wi-Fi name\" type=\"text\"/>\r\n""                    </td>\r\n""                </tr>\r\n""                <tr>\r\n""                    <td>\r\n""                        Wi-Fi&nbsp;&nbsp;&nbsp;&nbsp;Pwd:\r\n""                        <input name=\"PASSWORD\" placeholder=\"input Wi-Fi Password\" type=\"password\"/>\r\n""                    </td>\r\n""                </tr>\r\n""            </table>\r\n""            <button style=\"display:block;margin:0 auto\" type=\"submit\" value=\"Submit\">\r\n""                Confirm\r\n""            </button>\r\n""        </form>\r\n""    </body>\r\n""</html>";//配网完成
char* finish_html = "<!DOCTYPE html>\r\n""<html>\r\n""    <head>\r\n""        <meta charset=\"utf-8\" content=\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" name=\"viewport\"/>\r\n""        <title>\r\n""            ZCM IOT WiFi Config\r\n""        </title>\r\n""    </head>\r\n""    <body style=\"background: #00F948\">\r\n""        <div align=\"center\">\r\n""            <br><br>\r\n""            <font>\r\n""                ZCM IOT WiFi Config\r\n""            </font>\r\n""            <br/>\r\n""            <font>\r\n""                E-mail: wxhntmy@163.com\r\n""            </font>\r\n""            <br/>\r\n""            <br/>\r\n""            <font>\r\n""                Connecting to Wi-Fi, the connection is complete after the LED flashes three times!\r\n""                <br/>\r\n""                Steady on means the connection failed, please re-enter!\r\n""                <br/><br>\r\n""                <a href=\"WebConfig.html\" text-decoration=\"none\">\r\n""                    <button formtarget=\"_self\" style=\"display:block;margin:0 auto\">\r\n""                        Re-distribution Network\r\n""                    </button>\r\n""                </a>\r\n""                <br/>\r\n""                <a href=\"/\">\r\n""                    Back Home\r\n""                </a>\r\n""            </font>\r\n""        </div>\r\n""    </body>\r\n""</html>";

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 = "<!DOCTYPE html>\r\n""<html>\r\n""    <head>\r\n""        <meta charset=\"utf-8\" content=\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" name=\"viewport\"/>\r\n""        <title>\r\n""            ZCM IOT WiFi Config\r\n""        </title>\r\n""    </head>\r\n""    <body style=\"background: #00F948\">\r\n""        <div align=\"center\"><br/><br/>\r\n""            <font>\r\n""                ZCM IOT WiFi Config\r\n""            </font>\r\n""            <br/>\r\n""            <font>\r\n""                E-mail: wxhntmy@163.com\r\n""            </font>\r\n""            <br/>\r\n""            <br/>\r\n""            <a href=\"WebConfig.html\" text-decoration=\"none\">\r\n""                <button formtarget=\"_self\" style=\"display:block;margin:0 auto\">\r\n""                    Start Config\r\n""                </button>\r\n""            </a>\r\n""           <br/>\r\n""        </div>\r\n""    </body>\r\n""</html>";
//配网页面
char* config_html = "<!DOCTYPE html>\r\n""<html>\r\n""    <head>\r\n""        <meta charset=\"utf-8\" content=\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" name=\"viewport\"/>\r\n""        <title>\r\n""            ZCM IOT WiFi Config\r\n""        </title>\r\n""    </head>\r\n""    <body style=\"background: #00F948\">\r\n""        <div align=\"center\">\r\n""         <br><br>\r\n""            <font>\r\n""                ZCM IOT WiFi Config\r\n""            </font>\r\n""            <br/>\r\n""            <font>\r\n""                E-mail: wxhntmy@163.com\r\n""            </font>\r\n""            <br/>\r\n""            <br/>\r\n""        </div>\r\n""        <form action=\"WiFiConfig.html\" enctype=\"application/x-www-form-urlencoded\" method=\"post\">\r\n""            <table align=\"center\" border=\"0\" cellspacing=\"10\">\r\n""                <tr>\r\n""                    <td>\r\n""                        Wi-Fi Name:\r\n""                        <input name=\"SSID\" placeholder=\"input Wi-Fi name\" type=\"text\"/>\r\n""                    </td>\r\n""                </tr>\r\n""                <tr>\r\n""                    <td>\r\n""                        Wi-Fi&nbsp;&nbsp;&nbsp;&nbsp;Pwd:\r\n""                        <input name=\"PASSWORD\" placeholder=\"input Wi-Fi Password\" type=\"password\"/>\r\n""                    </td>\r\n""                </tr>\r\n""            </table>\r\n""            <button style=\"display:block;margin:0 auto\" type=\"submit\" value=\"Submit\">\r\n""                Confirm\r\n""            </button>\r\n""        </form>\r\n""    </body>\r\n""</html>";//配网完成
char* finish_html = "<!DOCTYPE html>\r\n""<html>\r\n""    <head>\r\n""        <meta charset=\"utf-8\" content=\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" name=\"viewport\"/>\r\n""        <title>\r\n""            ZCM IOT WiFi Config\r\n""        </title>\r\n""    </head>\r\n""    <body style=\"background: #00F948\">\r\n""        <div align=\"center\">\r\n""            <br><br>\r\n""            <font>\r\n""                ZCM IOT WiFi Config\r\n""            </font>\r\n""            <br/>\r\n""            <font>\r\n""                E-mail: wxhntmy@163.com\r\n""            </font>\r\n""            <br/>\r\n""            <br/>\r\n""            <font>\r\n""                Connecting to Wi-Fi, the connection is complete after the LED flashes three times!\r\n""                <br/>\r\n""                Steady on means the connection failed, please re-enter!\r\n""                <br/><br>\r\n""                <a href=\"WebConfig.html\" text-decoration=\"none\">\r\n""                    <button formtarget=\"_self\" style=\"display:block;margin:0 auto\">\r\n""                        Re-distribution Network\r\n""                    </button>\r\n""                </a>\r\n""                <br/>\r\n""                <a href=\"/\">\r\n""                    Back Home\r\n""                </a>\r\n""            </font>\r\n""        </div>\r\n""    </body>\r\n""</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_ENABLEespconn_secure_sent(ptrespconn, pbuf, length);
#elseespconn_sent(ptrespconn, pbuf, length);
#endif} else {#ifdef SERVER_SSL_ENABLEespconn_secure_sent(ptrespconn, httphead, length);
#elseespconn_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_ENABLEespconn_secure_sent(ptrespconn, pbuf, length);
#elseespconn_sent(ptrespconn, pbuf, length);
#endif} else {#ifdef SERVER_SSL_ENABLEespconn_secure_sent(ptrespconn, httphead, length);
#elseespconn_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参数会转码成+号,+号转码成%2Bstrrpc(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, "<meta charset='UTF-8'>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, "<meta charset='UTF-8'>Connect Success!");www_data_send(ptrespconn, true, finish_html);}else if(sta == STATION_WRONG_PASSWORD){//www_data_send(ptrespconn, true, "<meta charset='UTF-8'>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模式,不保存到flashwifi_set_opmode(STATIONAP_MODE);//设置为STATION+AP模式,并保存到flashos_memset(&soft_ap_Config, 0, sizeof(struct softap_config)); // AP参数结构体 = 0soft_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_OPENsoft_ap_Config.beacon_interval = 100;//信标间隔,默认为100soft_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 接口配置,不保存到 Flashwifi_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

2、配网首页

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

3、配网页面

4、配网完成页面

ESP8266 NonOS-SDK Web配网相关推荐

  1. ESP8266 web配网微信小程序配网 全平台配网库 arduino 傻瓜式通用库

    wifi_link_tool esp8266通用配网库 (arduino) 库地址:点击进入GitHub 这是一个为esp8266设计的通用配网库 该库免费提供 使用请注明出处 允许毕业设计使用本库 ...

  2. ESP8266的Web配网以及强制门户的实现(连接wifi自动打开网页)

    目录 前言 Web配网详解 强制门户详解 完整代码 实验效果 前言 1.Web配网概述 在应用到esp8266的场景,往往与wifi是离不开的,但用户的wifi账号密码又无从知晓,于是乎有了配网. 目 ...

  3. ESP8266开发之旅 网络篇⑭ web配网

    文章目录 1. 前言 2. Web配网(AP配网) 2.1 自定义AP配网 2.2 WiFiManager 3. 总结 授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大 ...

  4. 验证可用的ESP32/8266配网方式,开源代码,web配网,smartconfig配网

    web配网 设备内做了个小web服务器通过网页交换SSID和PWD.这个方式比较友好,不依赖外部app或小程序,保密性更好,产品可用性更好(苹果等个别手机不能打开配网页面可直接浏览器登陆192.168 ...

  5. ESP8266 Non-OS SDK开发探坑之四-用户非易失参数安全存储到flash

    ESP8266 Non-OS SDK开发探坑之四-用户非易失参数安全存储到flash [Starting with ESP8266 - Light a LED] [Starting with ESP8 ...

  6. ESP32 强制门户 WEB配网

    修改自此博主代码 参考博客 参考WEB配网的网页代码 ESP32学习笔记(23)--NVS(非易失性存储)接口使用 目录 前言 一.工程创建 1.获取源代码 2.新建一个ESP32的工程 3.移植代码 ...

  7. 【ESP8266】使用ESP8266 NONOS SDK的JSON API

    2016年9月30日更新:本人移植了cJSON到ESP8266的NONOS SDK,详情可以查看这篇文章: http://blog.csdn.net/yannanxiu/article/details ...

  8. ESP8266用EspTouch一键配网,断网自动恢复连接

    自动配网的实现 利用Arduino IDE自带的自动联网函数smartConfig() bool AutoConfig() {WiFi.begin();//如果觉得时间太长可改for (int i = ...

  9. STM32 ESP8266 微信Airkiss智能配网连接WiFi并接入OneNET

    你是否还在直接将wifi的ssid和密码直接写入STM32程序中通过串口发送给ESP8266?本文教你用微信Airkiss协议实现可视化地为ESP8266发送WiFi ssid和密码信息并连接WiFi ...

  10. ESP8266 Non-OS SDK 开发之旅 基础篇① 初识 Non-OS SDK,史上超级详细手把手教小白20分钟快速搭建SDK软件开发环境,完成第一个例子Hello World!

    文章目录 1.前言 2. SDK概述 2.1 SDK使用流程 2.2 ESP8266 HDK -- 硬件开发工具 2.3 ESP8266 SDK -- 软件开发工具包 2.3.1 Non-OS SDK ...

最新文章

  1. sqlite3 unicode转中文
  2. Oracle10g 管理系统全局区(SGA)
  3. centos7精简安装后使用发现没有killall命令
  4. 私有句柄表(内核对象,并非用户对象),全局句柄表
  5. 这些工具你利用好了吗?
  6. 应用ForkJoin –从最佳到快速
  7. hihocoder1477 闰秒
  8. mcjava盗版联机_我的世界java版联机版
  9. 操作系统相关机器语言基础部分
  10. Brave 浏览器宣布集成 IPFS 协议,它会取代 HTTP 吗?
  11. 得到 jason中 string 的值_简单高性能的Json解析器: Jason
  12. ISO七层协议与功能
  13. Liang-Barskey裁剪算法(计算机图形学)
  14. Canal.deployer 启动报错说CHARACTER SET 'utf8' COLLATE 'utf8_unico', expect null,rkdown编辑器
  15. 【数据分析实例】 7000 条北京的租房数据分析
  16. Java jsp导出Excel打开报格式或扩展名错误
  17. 图像处理算法之模糊检测
  18. win10如何显示html文件夹,Win10显示隐藏文件夹图标_Win10查看隐藏文件夹方法-192路由网...
  19. html中鼠标悬停图片变大,JavaScript通过mouseover()实现图片变大效果的示例
  20. 京东2019春招商业分析试卷[题目整理]

热门文章

  1. centos7安装有道词典
  2. 60秒学脑科学常识:《科学美国人》专栏文集
  3. 方差分析 交互效应和无交互效应
  4. event mpm php,apache的mpm的几种模式
  5. 打开CMD的方式及常用的DOS命令
  6. 在当前目录下 打开cmd
  7. ubuntu14.04安装skype4.3
  8. 画费氏数列螺线的代码
  9. 【WebGoat习题解析】Parameter Tampering-Bypass HTML Field Restrictions
  10. python背景颜色代码大全_Python实现转换图片背景颜色代码