[⽹络篇]ESP8266-SDK教程(六)之⽹页配置Wi-Fi名称和密码
这个周末有点忙,明天就是新的⼀周了,今晚更新⼀下⽂章!在上篇⽂章中有⼀点⼩⼩的历史遗留问题,不知道⼤家有没有⾃⼰实现出来,今天就给⼤家说⼀说⽹页配置Wi-Fi是怎么实现的,最近也是⽐较忙,⼿头有点⼩项⽬,今天抽点时间给⼤家讲⼀下~
开始之前,照例我们还是先了解⼀下基础知识吧,既然这⾥我们是⽤⽹页就配置,那么我们就有必要了解⼀下浏览器与Web Server之间是怎样通信的,相信每个⼈都有过在地址栏输⼊⽹址的时候,⽽且会经常看见"http"、"https"等字样,那么你有没有深⼊去了解⼀下这⼏个字母是什么意思呢?为什么⽹址的前⾯会加⼊这⼏个字母?可能很多⼈都是知道有,但是具体是什么作⽤没好好去了解,那么这⾥就简单给⼤家科普⼀下,毕竟我也不是专业的对这块知识也是停留在知道了解懂点的⽔平上。
⾸先我们需要先知道"http"、"https"是什么意思,戳卡⽚了解⼀下~
看完后是不是有点恍然⼤悟了?是不是觉得也没那么⾼⼤上了?其实,就是⼀种传输协议,不过传输的内容多以⽹页居多,http是在TCP/IP传输层之上的应⽤层协议,所以最根本的还是回到了TCP/IP通信,只不过http做了很多规范,包括请求格式,响应格式,状态码等等,http协议有⼀套很完整的规范,⼤家可以在这个规范之下传输数据,我们本篇⽂章虽然写着是⽹页配置,但是在界⾯之下的数据都是在http规范之下进⾏传输的,然后我们在Web Server(ESP8266)端进⾏数据解析,最后得到我们想要的信息。
先来简单看⼀下流程吧,做了⼀个草图,PS⽔平不佳,够⽤⽔平~
流程就是这个样⼦,通过⽹页发送SSID和PWD给ESP8266,ESP8266解析以后得到SSID和PWD去连接Wi-Fi,流程没多少东西,下⾯我们来看每⼀步是如何实现的!
⾸先是我们需要打开这个⽹页,但是我们该怎么样打开呢?⽹址是什么呢?可能⼤家会有这样的疑问,但是你有没有配置过家⾥的路由器呢?如果有的话,其实跟那个是⼀样的道理,没有配置的过的,我就给⼤家说⼀下,要知道的是在我们的ESP8266连接上路由器之前,我们是不可能在路由器这个局域⽹之下到这个设备的,所以我们去访问路由器下的⼦设备是不可能实现的,所以ESP8266应该是在AP模式,我们需要⽤⼿机或者PC去连接ESP8266,然后我们去访问ESP8266在AP模式下的IP地址才能打开这个可以配置的⽹页,就像我们家⾥的路由器,有⼀个固定的IP是去设置⼀些路由器参数的,这⾥原理是相同的。
然后我们打开这个⽹页,但是这个⽹页是保存在哪呢?其实就像你家⾥的路由器⼀样,这个配置⽹页都是保存在设备当中的,可能家⾥的路由器可存储空间⽐较⼤,还跑着OpenWRT系统,但是我们ESP8266是⼀样可以去实现的,我们需要将这个写好的⽹页,保存到ESP8266的flash当中,当ESP8266收到http请求时,我们再将这个⽹页从flash中读出来,发送给浏览器,可能有些⼈觉得有点不可思议,其实⽹页本⾝就是⼀个⽂件,flash就是存储⽂件的,我们既然可以写固件,那么同样可以写很
多别的东西,此时ESP8266就是⼀个很⼩的Web Server,处理来⾃浏览器的http请求,然后按照⼀定格式返回具体的⽹页,或者其他数据,这些都是通过TCP传输的。
那么我们了解了整个流程,也知道了⽹页是在哪保存着,那我们现在就却⼀个⽹页了,⽹页不要写的很复杂,因为ESP8266的flash是有限的,我们不能占⽤太⼤的地⽅,某些地⽅还是要存储我们编译好的程序的,⼤家应该也会写⼀点简单的⽹页吧?HTML是超⽂本标记语⾔,通过⼀些标签来实现特定的显⽰内容或者格式,不懂的可以稍微看⼀下,或者想实现什么功能就是百度⼀下,当然我这⾥嘛,就是⽐较熟悉了,因为从初中开始我就对做⼀个个⼈主页很感兴趣,所以没事也会看看这⽅⾯的知识,⼤家先看看这个界⾯吧,我也是简单⼀写。
就⼀个很简单的表格,填完以后,按下按键,表格中的内容就会以http协议的格式发送给ESP8266,这不是重要的,我们看⼀下ESP8266端是如何处理我们通过⽹页发送的数据。
直接上代码吧~
1/*********************
2 *      DEFINES
3 *********************/
4#define INDEX_SIZE    4410
5#define WEBCONFIG_SIZE    4526
6#define WIFIDONE_SIZE    4266
7
8/**********************
9 *      TYPEDEFS
10 **********************/
11static struct espconn webserver_espconn;
12static esp_tcp webserver_esptcp;
13/**********************
14 *  STATIC PROTOTYPES
15 **********************/
16static void webconfig_get_wifi_ssid_pwd(char* urlparam);
17static void softAP_init(void);
18static bool parse_url(char *precv, URL_Frame *purl_frame);
19static void webserver_recv(void *arg, char *pusrdata, unsigned short length);
20static void data_send(void *arg, bool responseOK, char *psend);
21static bool parse_url(char *precv, URL_Frame *purl_frame);
22static bool save_data(char *precv, uint16 length);
23static bool check_data(char *precv, uint16 length);
24static void webserver_recon(void *arg, sint8 err);
25static void webserver_discon(void *arg);
26static void webserver_listen(void *arg);
27/************************
28 *  STATIC VARIABLES  *
29 ************************/
30static char *precvbuffer;
31static uint32 dat_sumlength = 0;
32
33/**********************
34 *      MACROS
35 **********************/
36
37/**********************
38 *  GLOBAL FUNCTIONS
39 **********************/
40void ICACHE_FLASH_ATTR
41 user_webserver_init(uint32 port){
42
43    softAP_init();
44
tcp ip协议设置怎么填
45    pe = ESPCONN_TCP;
46    webserver_espconn.state = ESPCONN_NONE;
47    webserver_p = &webserver_esptcp;
48    webserver_p->local_port = port;
49    espconn_regist_connectcb(&webserver_espconn, webserver_listen);
50    espconn_regist_reconcb(&webserver_espconn,webserver_recon);
51
52    espconn_accept(&webserver_espconn);
53 }
54
55/**********************
56 *  STATIC FUNCTIONS
57 **********************/
58/*
59 * softAP模式初始化代码
60*/
61static void ICACHE_FLASH_ATTR
62 softAP_init(void){
63struct softap_config soft_ap_Config;
64
65    wifi_set_opmode_current(SOFTAP_MODE);//设置为AP模式,不保存到flash
66//    wifi_set_opmode(SOFTAP_MODE);//设置为AP模式,并保存到flash
67
68    soft_ap_Config.ssid_len = 14;//热点名称长度,与你实际的名称长度⼀致就好
69    os_strcpy(soft_ap_Config.ssid,"zhihu-IAMLIUBO");//实际热点名称设置,可以根据你的需要来
70    os_strcpy(soft_ap_Config.password,"imliubo123");//热点密码设置
71    soft_ap_Config.authmode = AUTH_WPA2_PSK;//设置权限模式,AUTH_WPA2_PSK这是⼀种加密算法
72    soft_ap_Config.beacon_interval = 100;//信标间隔,默认为100
73    soft_ap_Config.channel = 1;//信道,共⽀持1~13个信道
74    soft_ap_Config.max_connection = 2;//最⼤连接数量,最⼤⽀持四个,默认四个
75    soft_ap_Config.ssid_hidden = 0;//隐藏SSID,0:不隐藏  1:隐藏
76
77    wifi_softap_set_config_current(&soft_ap_Config);//设置 Wi-Fi SoftAP 接⼝配置,不保存到 Flash
78//    wifi_softap_set_config(&soft_ap_Config);//设置 Wi-Fi SoftAP 接⼝配置,保存到 Flash
79
80    os_printf("\r\nSSID: zhihu-IAMLIUBO\r\nPWD: imliubo123\r\n");
81 }
82
83static void ICACHE_FLASH_ATTR
84 webserver_recv(void *arg, char *pusrdata, unsigned short length)
85 {
86    URL_Frame *pURL_Frame = NULL;
87char *pParseBuffer = NULL;
88char *html = NULL;
89    SpiFlashOpResult ret = 0;
90
91    os_printf("\r\n\r\nlength:%d\r\n", length);
92    os_printf("recv:%s", pusrdata);
93
94
95    pURL_Frame = (URL_Frame *)os_zalloc(sizeof(URL_Frame));
96
97    parse_url(pusrdata, pURL_Frame);
98    os_printf("\r\nType[%d]\r\n", pURL_Frame->Type);
99    os_printf("pSelect[%s]\r\n", pURL_Frame->pSelect);
100    os_printf("pCommand[%s]\r\n", pURL_Frame->pCommand);
101    os_printf("pFilename[%s]\r\n", pURL_Frame->pFilename);
102
103switch (pURL_Frame->Type) {
104case GET:
105            os_printf("We have a GET request.\n");
106if(pURL_Frame->pFilename[0] == 0){
107                    html = (char *)os_zalloc(INDEX_SIZE);
108if(html == NULL){
109                        os_printf("os_zalloc error!\r\n");
110goto _temp_exit;
111                    }
112// Flash read/write has to be aligned to the 4-bytes boundary
113                    ret = spi_flash_read(508*4096, (uint32 *)html, INDEX_SIZE);  // start address:0x10000 + 0xC0000
114if(ret != SPI_FLASH_RESULT_OK){
115                        os_printf("spi_flash_read err:%d\r\n", ret);
116                        os_free(html);
117                        html = NULL;
118goto _temp_exit;
119                    }
120                    html[INDEX_SIZE] = 0;  // put 0 to the end
121                    data_send(arg, true, html);
122                    os_free(html);
123                    html = NULL;
124                }
125if(strncmp(pURL_Frame->pFilename, "WebConfig.html", strlen("WebConfig.html")) == 0){
126                    html = (char *)os_zalloc(WEBCONFIG_SIZE);
127if(html == NULL){
128                        os_printf("os_zalloc error!\r\n");
129goto _temp_exit;
130                    }
131// Flash read/write has to be aligned to the 4-bytes boundary
132                    ret = spi_flash_read(510*4096, (uint32 *)html, WEBCONFIG_SIZE);  // start address:0x10000 + 0xC0000 133if(ret != SPI_FLASH_RESULT_OK){
134                        os_printf("spi_flash_read err:%d\r\n", ret);
135                        os_free(html);
136                        html = NULL;
137goto _temp_exit;
138                    }
139                    html[WEBCONFIG_SIZE] = 0;  // put 0 to the end
140                    data_send(arg, true, html);
141                    os_free(html);
142                    html = NULL;
143                }
144break;
145
146case POST:
147            os_printf("We have a POST request.\r\n");
148if(strncmp(pURL_Frame->pCommand, "connect-wifi", strlen("connect-wifi")) == 0){
149                os_printf("connect wifi\r\n");
150                webconfig_get_wifi_ssid_pwd(pusrdata);
151                html = (char *)os_zalloc(WIFIDONE_SIZE);
152if(html == NULL){
153                    os_printf("os_zalloc error!\r\n");
154goto _temp_exit;
155                }
156                ret = spi_flash_read(512*4096, (uint32 *)html, WIFIDONE_SIZE);  // start address:0x10000 + 0xC0000 157if(ret != SPI_FLASH_RESULT_OK){
158                    os_printf("spi_flash_read err:%d\r\n", ret);
159                    os_free(html);
160                    html = NULL;
161goto _temp_exit;
162                }
163                html[WIFIDONE_SIZE] = 0;  // put 0 to the end
164                data_send(arg, true, html);
165                os_free(html);
166                html = NULL;
167            }
168break;
169    }
170    _temp_exit:
171        ;
172if(pURL_Frame != NULL){
173        os_free(pURL_Frame);
174        pURL_Frame = NULL;
175    }
176
177 }
178
179static void ICACHE_FLASH_ATTR
180 webconfig_get_wifi_ssid_pwd(char* urlparam)
181 {
182char *p = NULL, *q = NULL;
183char ssid[10], pass[15];
184
185    os_memset(ssid, 0, sizeof(ssid));
186    os_memset(pass, 0, sizeof(pass));
187
188    p = (char *)os_strstr(urlparam, "SSID=");
189    q = (char *)os_strstr(urlparam, "PASSWORD=");
190if ( p == NULL || q == NULL ){
191return;
192    }
193    os_memcpy(ssid, p + 5, q - p - 6);
194    os_memcpy(pass, q + 9, os_strlen(urlparam) - (q - urlparam) - 9);
195    os_printf("ssid[%s]pass[%s]\r\n", ssid, pass);
196
197    wifi_set_opmode(STATION_MODE);
198struct station_config stConf;
199    stConf.bssid_set = 0;
200    os_memset(&stConf.ssid, 0, sizeof(stConf.ssid));
201    os_memset(&stConf.password, 0, sizeof(stConf.password));
202
203    os_memcpy(&stConf.ssid, ssid, os_strlen(ssid));
204    os_memcpy(&stConf.password, pass, os_strlen(pass));
205
206    wifi_station_set_config(&stConf);
207//重启
208    system_restart();
209 }
210/******************************************************************************
211 * FunctionName : parse_url
212 * Description  : parse the received data from the server
213 * Parameters  : precv -- the received data
214 *                purl_frame -- the result of parsing the url
215 * Returns      : none
216*******************************************************************************/
217static bool ICACHE_FLASH_ATTR
218 parse_url(char *precv, URL_Frame *purl_frame)
219 {
220char *str = NULL;
221    uint8 length = 0;
222char *pbuffer = NULL;
223char *pbufer = NULL;
224
225if (purl_frame == NULL || precv == NULL) {
226return false;
227    }
228
229    pbuffer = (char *)os_strstr(precv, "Host:");
230
231if (pbuffer != NULL) {
232        length = pbuffer - precv;
233        pbufer = (char *)os_zalloc(length + 1);
234        pbuffer = pbufer;
235        os_memcpy(pbuffer, precv, length);
236        os_memset(purl_frame->pSelect, 0, URLSize);
237        os_memset(purl_frame->pCommand, 0, URLSize);
238        os_memset(purl_frame->pFilename, 0, URLSize);
239
240if (os_strncmp(pbuffer, "GET ", 4) == 0) {
241            purl_frame->Type = GET;
242            pbuffer += 4;
243        } else if (os_strncmp(pbuffer, "POST ", 5) == 0) {
244            purl_frame->Type = POST;
245            pbuffer += 5;
246        }else{
247return false;
248        }
249
250        pbuffer ++;
251        str = (char *)os_strstr(pbuffer, "HTTP");
252
253if (str != NULL) {
254            length = str - pbuffer - 1;
255            os_memcpy(purl_frame->pFilename, pbuffer, length);
256        }
257
258        os_free(pbufer);
259    }
260
261    pbuffer = (char *)os_strstr(precv, "SSID");
262if (pbuffer != NULL) {
263        purl_frame->Type = POST;
264        os_memcpy(purl_frame->pCommand, "connect-wifi", strlen("connect-wifi"));
265        os_free(pbufer);
266    }
267
268 }
269/******************************************************************************
270 * FunctionName : data_send
271 * Description  : processing the data as http format and send to the client or server
272 * Parameters  : arg -- argument to set for client or server
273 *                responseOK -- true or false
274 *                psend -- The send data
275 * Returns      :
276*******************************************************************************/
277static void ICACHE_FLASH_ATTR
278 data_send(void *arg, bool responseOK, char *psend)
279 {
280    uint16 length = 0;
281char *pbuf = NULL;
282char httphead[256];
283struct espconn *ptrespconn = arg;
284    os_memset(httphead, 0, 256);
285
286if (responseOK) {
287        os_sprintf(httphead,
288"HTTP/1.0 200 OK\r\nContent-Length: %d\r\nServer: lwIP/1.4.0\r\n",
289                    psend ? os_strlen(psend) : 0);
290
291if (psend) {
292            os_sprintf(httphead + os_strlen(httphead),
293"Content-type: text/html; charset=utf-8\r\nPragma: no-cache\r\n\r\n");
294            length = os_strlen(httphead) + os_strlen(psend);
295            pbuf = (char *)os_zalloc(length + 1);
296            os_memcpy(pbuf, httphead, os_strlen(httphead));
297            os_memcpy(pbuf + os_strlen(httphead), psend, os_strlen(psend));
298        } else {
299            os_sprintf(httphead + os_strlen(httphead), "\n");
300            length = os_strlen(httphead);
301        }
302    } else {
303        os_sprintf(httphead, "HTTP/1.0 400 BadRequest\r\nContent-Length: 0\r\nServer: lwIP/1.4.0\r\n\n"); 304        length = os_strlen(httphead);
305    }
306
307if (psend) {
308        espconn_sent(ptrespconn, pbuf, length);
309    } else {
310        espconn_sent(ptrespconn, httphead, length);
311    }
312
313if (pbuf) {
314        os_free(pbuf);
315        pbuf = NULL;
316    }
317 }
其中webserver_recv函数就是处理浏览器发来的各种http请求,我这⾥实际写了三个页⾯:⾸页、配置页⾯、配置完成页⾯,所以处理的有点多,spi_flash_read函数是将保存在flash中的⽹页读出来,可以看出我是从三个不同的地址读出来的⽹页,这个地址是根据你将⽹页写在了什么位置⽽去计算的,可以看⼀下我将三个⽹页烧录在了什么位置:
其中makingfun.html就是⾸页,我是烧录在了0x1FC000地址,那在代码中是从哪⼀个地⽅读出的呢?
spi_flash_read(508*4096, (uint32 *)html, INDEX_SIZE);
就是508x4096这个地址,0x1FC000是508x4096结果的⼗六进制,在ESP8266 flash操作中是4字节对齐的,⼀个扇区4KB,每次擦写都需要整个扇区去操作。我们后⾯再详细说⼀下关于flash操作的⼀些注意事项。
parse_url函数是解析http请求中携带的URL参数、请求⽅法、请求的⽂件名称,主要使⽤的是C库中的字符串处理函数,然后根据http请求格式中固定的字段去解析出我们实际传进来的参数。
webconfig_get_wifi_ssid_pwd函数就是解析我们填在表格中的Wi-Fi名称和密码了,也是使⽤的C库中的字符串处理函数,其中“SSID”和“PASSWORD”是表格属性,等号后边是我们填写的内容,“&”不是我们填写的,所以计算的时候需要将它剔除掉。
最后还需要注意⼀点的是,这个三个宏定义:
1#define INDEX_SIZE    1437
2#define WEBCONFIG_SIZE    1541
3#define WIFIDONE_SIZE    1293
这是我们写好的⽹页的实际⼤⼩,也就是我们实际写到flash当中的⽹页⼤⼩,这⾥需要根据你实际的⽹页⼤⼩去更改。
下⾯我们看⼀下三个页⾯的HTML代码:
⾸页代码:
<!DOCTYPE html>
<html>
<head>
<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"/>
<title>
IAMLIUBO的神奇物联⽹之旅
</title>
</head>
<body>
<div align="center">
<font>
IAMLIUBO
</font>
<br/>
<font>
E-mail:
</font>
<br/>
<a href="zhuanlan.zhihu/imliubo-magic-IoT-Tutorial">
IAMLIUBO的神奇物联⽹之旅
</a>
<br/>
<p>
欢迎关注我的知乎专栏,我会在专栏不定期分享⼀些⽂章,其中有包括物联⽹⽅⾯的,也有会有⼀些⾃⼰开发经验分享,关注专栏,与我⼀起进步!
<br/>
唯有爱与科技不可辜负。
<br/>
技术交流或者项⽬合作可以私信或者邮件联系我。
<br/>
点击按钮开始配⽹
</p>
<a href="WebConfig.html" text-decoration="none">
<button formtarget="_self" >
开始配⽹
</button>
</a>
</div>
</body>
</html>
配置⽹页代码:
<!DOCTYPE html>
<html>
<head>
<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"/>
<title>
IAMLIUBO的神奇物联⽹之旅
</title>
</head>
<body>
<div align="center">
<font>
IAMLIUBO
</font>
<br/>
<font>
E-mail:
</font>

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。