ESP8266 WEB 配网(转)
/********************* * DEFINES *********************/ #define INDEX_SIZE 4410 #define WEBCONFIG_SIZE 4526 #define WIFIDONE_SIZE 4266 /********************** * TYPEDEFS **********************/ static struct espconn webserver_espconn; static esp_tcp webserver_esptcp; /********************** * STATIC PROTOTYPES **********************/ static void webconfig_get_wifi_ssid_pwd(char* urlparam); static void softAP_init(void); static bool parse_url(char *precv, URL_Frame *purl_frame); static void webserver_recv(void *arg, char *pusrdata, unsigned short length); static void data_send(void *arg, bool responseOK, char *psend); static bool parse_url(char *precv, URL_Frame *purl_frame); static bool save_data(char *precv, uint16 length); static bool check_data(char *precv, uint16 length); static void webserver_recon(void *arg, sint8 err); static void webserver_discon(void *arg); static void webserver_listen(void *arg); /************************ * STATIC VARIABLES * ************************/ static char *precvbuffer; static uint32 dat_sumlength = 0; /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ void ICACHE_FLASH_ATTR user_webserver_init(uint32 port){ softAP_init(); webserver_espconn.type = ESPCONN_TCP; webserver_espconn.state = ESPCONN_NONE; webserver_espconn.proto.tcp = &webserver_esptcp; webserver_espconn.proto.tcp->local_port = port; espconn_regist_connectcb(&webserver_espconn, webserver_listen); espconn_regist_reconcb(&webserver_espconn,webserver_recon); espconn_accept(&webserver_espconn); } /********************** * STATIC FUNCTIONS **********************/ /* * softAP模式初始化代码 */ static void ICACHE_FLASH_ATTR softAP_init(void){ struct softap_config soft_ap_Config; wifi_set_opmode_current(SOFTAP_MODE);//设置为AP模式,不保存到flash // wifi_set_opmode(SOFTAP_MODE);//设置为AP模式,并保存到flash soft_ap_Config.ssid_len = 14;//热点名称长度,与你实际的名称长度一致就好 os_strcpy(soft_ap_Config.ssid,"zhihu-IAMLIUBO");//实际热点名称设置,可以根据你的需要来 os_strcpy(soft_ap_Config.password,"imliubo123");//热点密码设置 soft_ap_Config.authmode = AUTH_WPA2_PSK;//设置权限模式,AUTH_WPA2_PSK这是一种加密算法 soft_ap_Config.beacon_interval = 100;//信标间隔,默认为100 soft_ap_Config.channel = 1;//信道,共支持1~13个信道 soft_ap_Config.max_connection = 2;//最大连接数量,最大支持四个,默认四个 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 os_printf("\r\nSSID: zhihu-IAMLIUBO\r\nPWD: imliubo123\r\n"); } static void ICACHE_FLASH_ATTR webserver_recv(void *arg, char *pusrdata, unsigned short length) { URL_Frame *pURL_Frame = NULL; char *pParseBuffer = NULL; char *html = NULL; SpiFlashOpResult ret = 0; os_printf("\r\n\r\nlength:%d\r\n", length); os_printf("recv:%s", pusrdata); pURL_Frame = (URL_Frame *)os_zalloc(sizeof(URL_Frame)); parse_url(pusrdata, pURL_Frame); 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"); if(pURL_Frame->pFilename[0] == 0){ html = (char *)os_zalloc(INDEX_SIZE); if(html == NULL){ os_printf("os_zalloc error!\r\n"); goto _temp_exit; } // Flash read/write has to be aligned to the 4-bytes boundary ret = spi_flash_read(508*4096, (uint32 *)html, INDEX_SIZE); // start address:0x10000 + 0xC0000 if(ret != SPI_FLASH_RESULT_OK){ os_printf("spi_flash_read err:%d\r\n", ret); os_free(html); html = NULL; goto _temp_exit; } html[INDEX_SIZE] = 0; // put 0 to the end data_send(arg, true, html); os_free(html); html = NULL; } if(strncmp(pURL_Frame->pFilename, "WebConfig.html", strlen("WebConfig.html")) == 0){ html = (char *)os_zalloc(WEBCONFIG_SIZE); if(html == NULL){ os_printf("os_zalloc error!\r\n"); goto _temp_exit; } // Flash read/write has to be aligned to the 4-bytes boundary ret = spi_flash_read(510*4096, (uint32 *)html, WEBCONFIG_SIZE); // start address:0x10000 + 0xC0000 if(ret != SPI_FLASH_RESULT_OK){ os_printf("spi_flash_read err:%d\r\n", ret); os_free(html); html = NULL; goto _temp_exit; } html[WEBCONFIG_SIZE] = 0; // put 0 to the end data_send(arg, true, html); os_free(html); html = NULL; } break; case POST: os_printf("We have a POST request.\r\n"); if(strncmp(pURL_Frame->pCommand, "connect-wifi", strlen("connect-wifi")) == 0){ os_printf("connect wifi\r\n"); webconfig_get_wifi_ssid_pwd(pusrdata); html = (char *)os_zalloc(WIFIDONE_SIZE); if(html == NULL){ os_printf("os_zalloc error!\r\n"); goto _temp_exit; } ret = spi_flash_read(512*4096, (uint32 *)html, WIFIDONE_SIZE); // start address:0x10000 + 0xC0000 if(ret != SPI_FLASH_RESULT_OK){ os_printf("spi_flash_read err:%d\r\n", ret); os_free(html); html = NULL; goto _temp_exit; } html[WIFIDONE_SIZE] = 0; // put 0 to the end data_send(arg, true, html); os_free(html); html = NULL; } break; } _temp_exit: ; if(pURL_Frame != NULL){ os_free(pURL_Frame); pURL_Frame = NULL; } } static void ICACHE_FLASH_ATTR webconfig_get_wifi_ssid_pwd(char* urlparam) { char *p = NULL, *q = NULL; char ssid[10], pass[15]; 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); os_printf("ssid[%s]pass[%s]\r\n", ssid, pass); wifi_set_opmode(STATION_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(); } /****************************************************************************** * FunctionName : parse_url * Description : parse the received data from the server * Parameters : precv -- the received data * purl_frame -- the result of parsing the url * Returns : none *******************************************************************************/ static bool ICACHE_FLASH_ATTR 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 false; } 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; }else{ return false; } pbuffer ++; str = (char *)os_strstr(pbuffer, "HTTP"); if (str != NULL) { length = str - pbuffer - 1; os_memcpy(purl_frame->pFilename, pbuffer, length); } os_free(pbufer); } 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); } } /****************************************************************************** * FunctionName : data_send * Description : processing the data as http format and send to the client or server * Parameters : arg -- argument to set for client or server * responseOK -- true or false * psend -- The send data * Returns : *******************************************************************************/ static void ICACHE_FLASH_ATTR 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; charset=utf-8\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\nContent-Length: 0\r\nServer: lwIP/1.4.0\r\n\n"); length = os_strlen(httphead); } if (psend) { espconn_sent(ptrespconn, pbuf, length); } else { espconn_sent(ptrespconn, httphead, length); } if (pbuf) { os_free(pbuf); pbuf = NULL; } }

其中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”是表格属性,等号后边是我们填写的内容,“&”不是我们填写的,所以计算的时候需要将它剔除掉。
最后还需要注意一点的是,这个三个宏定义:
#define INDEX_SIZE 1437 #define WEBCONFIG_SIZE 1541 #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: imliubo@makingfun.xyz </font> <br/> <a href="https://zhuanlan.zhihu.com/imliubo-magic-IoT-Tutorial"> IAMLIUBO的神奇物联网之旅 </a> <br/> <p> 欢迎关注我的知乎专栏,我会在专栏不定期分享一些文章,其中有包括物联网方面的,也有会有一些自己开发经验分享,关注专栏,与我一起进步! <br/> 唯有爱与科技不可辜负。 <br/> 技术交流或者项目合作可以私信或者邮件联系我。 <br/> 点击按钮开始配网 </p> <a href="WebConfig.html" text-decoration="none"> <button formtarget="_self" style="display:block;margin:0 auto"> 开始配网 </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: imliubo@makingfun.xyz </font> <br/> <a href="https://zhuanlan.zhihu.com/imliubo-magic-IoT-Tutorial"> IAMLIUBO的神奇物联网之旅 </a> <br/> </div> <form action="WiFiConfig.html" enctype="application/x-www-form-urlencoded" method="post"> <table align="center" border="0" cellspacing="10"> <tr> <td> Wi-Fi名称: <input name="SSID" placeholder="在这里输入Wi-Fi名称" type="text"/> </td> </tr> <tr> <td> Wi-Fi密码: <input name="PASSWORD" placeholder="在这里输入Wi-Fi密码" type="password"/> </td> </tr> </table> <button style="display:block;margin:0 auto" type="submit" value="Submit"> 确认提交 </button> </form> </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: imliubo@makingfun.xyz </font> <br/> <a href="https://zhuanlan.zhihu.com/imliubo-magic-IoT-Tutorial"> IAMLIUBO的神奇物联网之旅 </a> <br/> <font> 正在连接Wi-Fi,LED灯闪烁三次后连接完成! <br/> 常亮表示连接失败请重新输入! <br/> <a href="WebConfig.html" text-decoration="none"> <button formtarget="_self" style="display:block;margin:0 auto"> 重新配网 </button> </a> <br/> <a href="/"> 返回首页 </a> </font> </div> </body> </html>
作者:IAMLIUBO
链接:https://www.jianshu.com/p/760c01694245
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

浙公网安备 33010602011771号