2023年12月14日发(作者:)
[网络篇]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 **********************/
11 static struct espconn webserver_espconn;
12 static esp_tcp webserver_esptcp;
13 /**********************
14 * STATIC PROTOTYPES
15 **********************/
16 static void webconfig_get_wifi_ssid_pwd(char* urlparam);
17 static void softAP_init(void);
18 static bool parse_url(char *precv, URL_Frame *purl_frame);
19 static void webserver_recv(void *arg, char *pusrdata, unsigned short length);
20 static void data_send(void *arg, bool responseOK, char *psend);
21 static bool parse_url(char *precv, URL_Frame *purl_frame);
22 static bool save_data(char *precv, uint16 length);
23 static bool check_data(char *precv, uint16 length);
24 static void webserver_recon(void *arg, sint8 err);
25 static void webserver_discon(void *arg);
26 static void webserver_listen(void *arg);
27 /************************
28 * STATIC VARIABLES *
29 ************************/
30 static char *precvbuffer;
31 static uint32 dat_sumlength = 0;
32
33 /**********************
34 * MACROS
35 **********************/
36
37 /**********************
38 * GLOBAL FUNCTIONS
39 **********************/
40 void ICACHE_FLASH_ATTR
41 user_webserver_init(uint32 port){
42
43 softAP_init();
44
45 webserver_ = ESPCONN_TCP;
46 webserver_ = ESPCONN_NONE;
47 webserver_ = &webserver_esptcp; 48 webserver_->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 */
61 static void ICACHE_FLASH_ATTR
62 softAP_init(void){
63 struct 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__len = 14;//热点名称长度,与你实际的名称长度一致就好
69 os_strcpy(soft_ap_,"zhihu-IAMLIUBO");//实际热点名称设置,可以根据你的需要来
70 os_strcpy(soft_ap_rd,"imliubo123");//热点密码设置
71 soft_ap_de = AUTH_WPA2_PSK;//设置权限模式,AUTH_WPA2_PSK这是一种加密算法
72 soft_ap__interval = 100;//信标间隔,默认为100
73 soft_ap_l = 1;//信道,共支持1~13个信道
74 soft_ap__connection = 2;//最大连接数量,最大支持四个,默认四个
75 soft_ap__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("rnSSID: zhihu-IAMLIUBOrnPWD: imliubo123rn");
81 }
82
83 static void ICACHE_FLASH_ATTR
84 webserver_recv(void *arg, char *pusrdata, unsigned short length)
85 {
86 URL_Frame *pURL_Frame = NULL;
87 char *pParseBuffer = NULL;
88 char *html = NULL;
89 SpiFlashOpResult ret = 0;
90
91 os_printf("rnrnlength:%drn", 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("rnType[%d]rn", pURL_Frame->Type);
99 os_printf("pSelect[%s]rn", pURL_Frame->pSelect);
100 os_printf("pCommand[%s]rn", pURL_Frame->pCommand);
101 os_printf("pFilename[%s]rn", pURL_Frame->pFilename);
102
103 switch (pURL_Frame->Type) {
104 case GET:
105 os_printf("We have a GET request.n");
106 if(pURL_Frame->pFilename[0] == 0){
107 html = (char *)os_zalloc(INDEX_SIZE);
108 if(html == NULL){
109 os_printf("os_zalloc error!rn");
110 goto _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
114 if(ret != SPI_FLASH_RESULT_OK){
115 os_printf("spi_flash_read err:%drn", ret);
116 os_free(html);
117 html = NULL;
118 goto _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 }
125 if(strncmp(pURL_Frame->pFilename, "", strlen("")) == 0){
126 html = (char *)os_zalloc(WEBCONFIG_SIZE);
127 if(html == NULL){
128 os_printf("os_zalloc error!rn");
129 goto _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
133 if(ret != SPI_FLASH_RESULT_OK){
134 os_printf("spi_flash_read err:%drn", ret);
135 os_free(html);
136 html = NULL;137 goto _temp_exit;138 }139 html[WEBCONFIG_SIZE] = 0; // put 0 to the end140 data_send(arg, true, html);141 os_free(html);142 html = NULL;143 }144 break;145
146 case POST:147 os_printf("We have a POST ");148 if(strncmp(pURL_Frame->pCommand, "connect-wifi", strlen("connect-wifi")) == 0){149 os_printf("connect wifirn");150 webconfig_get_wifi_ssid_pwd(pusrdata);151 html = (char *)os_zalloc(WIFIDONE_SIZE);152 if(html == NULL){153 os_printf("os_zalloc error!rn");154 goto _temp_exit;155 }156 ret = spi_flash_read(512*4096, (uint32 *)html, WIFIDONE_SIZE); // start address:0x10000 + 0xC0000157 if(ret != SPI_FLASH_RESULT_OK){158 os_printf("spi_flash_read err:%drn", ret);159 os_free(html);160 html = NULL;161 goto _temp_exit;162 }163 html[WIFIDONE_SIZE] = 0; // put 0 to the end164 data_send(arg, true, html);165 os_free(html);166 html = NULL;167 }168 break;169 }170 _temp_exit:171 ;172 if(pURL_Frame != NULL){173 os_free(pURL_Frame);174 pURL_Frame = NULL;175 }176
177 }178
179 static void ICACHE_FLASH_ATTR180 webconfig_get_wifi_ssid_pwd(char* urlparam)181 {182 char *p = NULL, *q = NULL;183 char 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=");190 if ( p == NULL || q == NULL ){191 return;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]rn", ssid, pass);196
197 wifi_set_opmode(STATION_MODE);198 struct station_config stConf;199 _set = 0;200 os_memset(&, 0, sizeof());201 os_memset(&rd, 0, sizeof(rd));202
203 os_memcpy(&, ssid, os_strlen(ssid));204 os_memcpy(&rd, pass, os_strlen(pass));205
206 wifi_station_set_config(&stConf);207 //重启208 system_restart();209 }210 /******************************************************************************211 * FunctionName : parse_url212 * Description : parse the received data from the server213 * Parameters : precv -- the received data214 * purl_frame -- the result of parsing the url215 * Returns : none216 *******************************************************************************/217 static bool ICACHE_FLASH_ATTR218 parse_url(char *precv, URL_Frame *purl_frame)219 {220 char *str = NULL;221 uint8 length = 0;222 char *pbuffer = NULL;223 char *pbufer = NULL;224
225 if (purl_frame == NULL || precv == NULL) {226 return false;227 }228
229 pbuffer = (char *)os_strstr(precv, "Host:");230
231 if (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
240 if (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{247 return false;248 }249
250 pbuffer ++;251 str = (char *)os_strstr(pbuffer, "HTTP");252
253 if (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");262 if (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_send271 * Description : processing the data as http format and send to the client or server272 * Parameters : arg -- argument to set for client or server273 * responseOK -- true or false274 * psend -- The send data275 * Returns :276 *******************************************************************************/277 static void ICACHE_FLASH_ATTR278 data_send(void *arg, bool responseOK, char *psend)279 {280 uint16 length = 0;281 char *pbuf = NULL;282 char httphead[256];283 struct espconn *ptrespconn = arg;284 os_memset(httphead, 0, 256);285
286 if (responseOK) {287 os_sprintf(httphead,288 "HTTP/1.0 200 OKrnContent-Length: %drnServer: lwIP/1.4.0rn",289 psend ? os_strlen(psend) : 0);290
291 if (psend) {292 os_sprintf(httphead + os_strlen(httphead),293 "Content-type: text/html; charset=utf-8rnPragma: no-cachernrn");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 BadRequestrnContent-Length: 0rnServer: lwIP/1.4.0rnn");304 length = os_strlen(httphead);305 }306
307 if (psend) {308 espconn_sent(ptrespconn, pbuf, length);309 } else {310 espconn_sent(ptrespconn, httphead, length);311 }312
313 if (pbuf) {314 os_free(pbuf);315 pbuf = NULL;
316 }
317 }
其中webserver_recv函数就是处理浏览器发来的各种http请求,我这里实际写了三个页面:首页、配置页面、配置完成页面,所以处理的有点多,spi_flash_read函数是将保存在flash中
的网页读出来,可以看出我是从三个不同的地址读出来的网页,这个地址是根据你将网页写在了什么位置而去计算的,可以看一下我将三个网页烧录在了什么位置:
其中就是首页,我是烧录在了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代码:
首页代码:
IAMLIUBO的神奇物联网之旅
IAMLIUBO
E-mail: imliubo@
IAMLIUBO的神奇物联网之旅
欢迎关注我的知乎专栏,我会在专栏不定期分享一些文章,其中有包括物联网方面的,也有会有一些自己开发经验分享,关注专栏,与我一起进步!
唯有爱与科技不可辜负。
技术交流或者项目合作可以私信或者邮件联系我。
点击按钮开始配网
开始配网
配置网页代码:
IAMLIUBO的神奇物联网之旅
配网完成页面:
IAMLIUBO的神奇物联网之旅
上个演示视频:
视频可以去B站看了,后期比较长一点的视频都会放在B站上,因为知乎最长可以上传15分钟的视频,最大1G,所以有些比较长的视频就没法直接上传了,请谅解,代码稍后整理后我会
上传到我的GitHub仓。
最后欢迎大家去我的仓库点个Star,您的鼓励是我最大的动力~有问题可以私信我,或者提交issues。
QQ交流群:592587184


发布评论