[網(wǎng)絡(luò)篇]ESP8266-SDK教程(六)之網(wǎng)頁配置Wi-Fi名稱和密碼

這個周末有點(diǎn)忙奇徒,明天就是新的一周了雏亚,今晚更新一下文章!在上篇文章中有一點(diǎn)小小的歷史遺留問題摩钙,不知道大家有沒有自己實(shí)現(xiàn)出來罢低,今天就給大家說一說網(wǎng)頁配置Wi-Fi是怎么實(shí)現(xiàn)的,最近也是比較忙胖笛,手頭有點(diǎn)小項(xiàng)目网持,今天抽點(diǎn)時間給大家講一下~

開始之前,照例我們還是先了解一下基礎(chǔ)知識吧匀钧,既然這里我們是用網(wǎng)頁就配置翎碑,那么我們就有必要了解一下瀏覽器與Web Server之間是怎樣通信的,相信每個人都有過在地址欄輸入網(wǎng)址的時候之斯,而且會經(jīng)橙砧荆看見"http"、"https"等字樣,那么你有沒有深入去了解一下這幾個字母是什么意思呢?為什么網(wǎng)址的前面會加入這幾個字母茉帅?可能很多人都是知道有,但是具體是什么作用沒好好去了解涨冀,那么這里就簡單給大家科普一下,畢竟我也不是專業(yè)的對這塊知識也是停留在知道了解懂點(diǎn)的水平上麦萤。

首先我們需要先知道"http"鹿鳖、"https"是什么意思,戳卡片了解一下~

http_百度百科?baike.baidu.com

https_百度百科?baike.baidu.com
圖標(biāo)

看完后是不是有點(diǎn)恍然大悟了壮莹?是不是覺得也沒那么高大上了翅帜?其實(shí),就是一種傳輸協(xié)議命满,不過傳輸?shù)膬?nèi)容多以網(wǎng)頁居多涝滴,http是在TCP/IP傳輸層之上的應(yīng)用層協(xié)議,所以最根本的還是回到了TCP/IP通信,只不過http做了很多規(guī)范歼疮,包括請求格式杂抽,響應(yīng)格式,狀態(tài)碼等等韩脏,http協(xié)議有一套很完整的規(guī)范缩麸,大家可以在這個規(guī)范之下傳輸數(shù)據(jù),我們本篇文章雖然寫著是網(wǎng)頁配置骤素,但是在界面之下的數(shù)據(jù)都是在http規(guī)范之下進(jìn)行傳輸?shù)某锥茫缓笪覀冊赪eb Server(ESP8266)端進(jìn)行數(shù)據(jù)解析,最后得到我們想要的信息济竹。

先來簡單看一下流程吧,做了一個草圖霎槐,PS水平不佳送浊,夠用水平~

image

流程就是這個樣子,通過網(wǎng)頁發(fā)送SSID和PWD給ESP8266丘跌,ESP8266解析以后得到SSID和PWD去連接Wi-Fi袭景,流程沒多少東西,下面我們來看每一步是如何實(shí)現(xiàn)的闭树!

首先是我們需要打開這個網(wǎng)頁耸棒,但是我們該怎么樣打開呢?網(wǎng)址是什么呢报辱?可能大家會有這樣的疑問与殃,但是你有沒有配置過家里的路由器呢?如果有的話碍现,其實(shí)跟那個是一樣的道理幅疼,沒有配置的過的,我就給大家說一下昼接,要知道的是在我們的ESP8266連接上路由器之前爽篷,我們是不可能在路由器這個局域網(wǎng)之下找到這個設(shè)備的,所以我們?nèi)ピL問路由器下的子設(shè)備是不可能實(shí)現(xiàn)的慢睡,所以ESP8266應(yīng)該是在AP模式逐工,我們需要用手機(jī)或者PC去連接ESP8266,然后我們?nèi)ピL問ESP8266在AP模式下的IP地址才能打開這個可以配置的網(wǎng)頁漂辐,就像我們家里的路由器泪喊,有一個固定的IP是去設(shè)置一些路由器參數(shù)的,這里原理是相同的者吁。

然后我們打開這個網(wǎng)頁窘俺,但是這個網(wǎng)頁是保存在哪呢?其實(shí)就像你家里的路由器一樣,這個配置網(wǎng)頁都是保存在設(shè)備當(dāng)中的瘤泪,可能家里的路由器可存儲空間比較大灶泵,還跑著OpenWRT系統(tǒng),但是我們ESP8266是一樣可以去實(shí)現(xiàn)的对途,我們需要將這個寫好的網(wǎng)頁赦邻,保存到ESP8266的flash當(dāng)中,當(dāng)ESP8266收到http請求時实檀,我們再將這個網(wǎng)頁從flash中讀出來惶洲,發(fā)送給瀏覽器,可能有些人覺得有點(diǎn)不可思議膳犹,其實(shí)網(wǎng)頁本身就是一個文件恬吕,flash就是存儲文件的,我們既然可以寫固件须床,那么同樣可以寫很多別的東西铐料,此時ESP8266就是一個很小的Web Server,處理來自瀏覽器的http請求豺旬,然后按照一定格式返回具體的網(wǎng)頁钠惩,或者其他數(shù)據(jù),這些都是通過TCP傳輸?shù)摹?/p>

那么我們了解了整個流程族阅,也知道了網(wǎng)頁是在哪保存著篓跛,那我們現(xiàn)在就卻一個網(wǎng)頁了,網(wǎng)頁不要寫的很復(fù)雜坦刀,因?yàn)镋SP8266的flash是有限的愧沟,我們不能占用太大的地方,某些地方還是要存儲我們編譯好的程序的求泰,大家應(yīng)該也會寫一點(diǎn)簡單的網(wǎng)頁吧央渣?HTML是超文本標(biāo)記語言,通過一些標(biāo)簽來實(shí)現(xiàn)特定的顯示內(nèi)容或者格式渴频,不懂的可以稍微看一下芽丹,或者想實(shí)現(xiàn)什么功能就是百度一下,當(dāng)然我這里嘛卜朗,就是比較熟悉了拔第,因?yàn)閺某踔虚_始我就對做一個個人主頁很感興趣,所以沒事也會看看這方面的知識场钉,大家先看看這個界面吧蚊俺,我也是簡單一寫。

image

<figcaption style="margin-top: 0.66667em; padding: 0px 1em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">網(wǎng)頁配置ESP8266 WiFi密碼</figcaption>

就一個很簡單的表格逛万,填完以后泳猬,按下按鍵,表格中的內(nèi)容就會以http協(xié)議的格式發(fā)送給ESP8266,這不是重要的得封,我們看一下ESP8266端是如何處理我們通過網(wǎng)頁發(fā)送的數(shù)據(jù)埋心。

直接上代碼吧~

/*********************
 *      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);//設(shè)置為AP模式,不保存到flash
//  wifi_set_opmode(SOFTAP_MODE);//設(shè)置為AP模式忙上,并保存到flash

    soft_ap_Config.ssid_len = 14;//熱點(diǎn)名稱長度拷呆,與你實(shí)際的名稱長度一致就好
    os_strcpy(soft_ap_Config.ssid,"zhihu-IAMLIUBO");//實(shí)際熱點(diǎn)名稱設(shè)置,可以根據(jù)你的需要來
    os_strcpy(soft_ap_Config.password,"imliubo123");//熱點(diǎn)密碼設(shè)置
    soft_ap_Config.authmode = AUTH_WPA2_PSK;//設(shè)置權(quán)限模式疫粥,AUTH_WPA2_PSK這是一種加密算法
    soft_ap_Config.beacon_interval = 100;//信標(biāo)間隔茬斧,默認(rèn)為100
    soft_ap_Config.channel = 1;//信道,共支持1~13個信道
    soft_ap_Config.max_connection = 2;//最大連接數(shù)量梗逮,最大支持四個项秉,默認(rèn)四個
    soft_ap_Config.ssid_hidden = 0;//隱藏SSID,0:不隱藏  1:隱藏

    wifi_softap_set_config_current(&soft_ap_Config);//設(shè)置 Wi-Fi SoftAP 接口配置慷彤,不保存到 Flash
//  wifi_softap_set_config(&soft_ap_Config);//設(shè)置 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;
    }
}

其中webserver_recv函數(shù)就是處理瀏覽器發(fā)來的各種http請求,我這里實(shí)際寫了三個頁面:首頁瞬欧、配置頁面、配置完成頁面罢防,所以處理的有點(diǎn)多艘虎,spi_flash_read函數(shù)是將保存在flash中的網(wǎng)頁讀出來,可以看出我是從三個不同的地址讀出來的網(wǎng)頁咒吐,這個地址是根據(jù)你將網(wǎng)頁寫在了什么位置而去計算的野建,可以看一下我將三個網(wǎng)頁燒錄在了什么位置:

image

其中makingfun.html就是首頁,我是燒錄在了0x1FC000地址恬叹,那在代碼中是從哪一個地方讀出的呢候生?

spi_flash_read(508*4096, (uint32 *)html, INDEX_SIZE); 

就是508x4096這個地址,0x1FC000是508x4096結(jié)果的十六進(jìn)制绽昼,在ESP8266 flash操作中是4字節(jié)對齊的唯鸭,一個扇區(qū)4KB,每次擦寫都需要整個扇區(qū)去操作硅确。我們后面再詳細(xì)說一下關(guān)于flash操作的一些注意事項(xiàng)目溉。

parse_url函數(shù)是解析http請求中攜帶的URL參數(shù)、請求方法菱农、請求的文件名稱缭付,主要使用的是C庫中的字符串處理函數(shù),然后根據(jù)http請求格式中固定的字段去解析出我們實(shí)際傳進(jìn)來的參數(shù)循未。

webconfig_get_wifi_ssid_pwd函數(shù)就是解析我們填在表格中的Wi-Fi名稱和密碼了陷猫,也是使用的C庫中的字符串處理函數(shù),其中“SSID”和“PASSWORD”是表格屬性,等號后邊是我們填寫的內(nèi)容绣檬,“&”不是我們填寫的足陨,所以計算的時候需要將它剔除掉。

最后還需要注意一點(diǎn)的是河咽,這個三個宏定義:

#define INDEX_SIZE  1437
#define WEBCONFIG_SIZE  1541
#define WIFIDONE_SIZE   1293

這是我們寫好的網(wǎng)頁的實(shí)際大小钠右,也就是我們實(shí)際寫到flash當(dāng)中的網(wǎng)頁大小,這里需要根據(jù)你實(shí)際的網(wǎng)頁大小去更改忘蟹。

下面我們看一下三個頁面的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的神奇物聯(lián)網(wǎng)之旅
        </title>
    </head>
    <body>
        <div align="center">
            <font>
                IAMLIUBO
            </font>
            <br/>
            <font>
                E-mail: imliubo@makingfun.xyz
            </font>
            <br/>
            <a >
                IAMLIUBO的神奇物聯(lián)網(wǎng)之旅
            </a>
            <br/>
            <p>
                歡迎關(guān)注我的知乎專欄飒房,我會在專欄不定期分享一些文章,其中有包括物聯(lián)網(wǎng)方面的媚值,也有會有一些自己開發(fā)經(jīng)驗(yàn)分享狠毯,關(guān)注專欄,與我一起進(jìn)步褥芒!
                <br/>
                唯有愛與科技不可辜負(fù)嚼松。
                <br/>
                技術(shù)交流或者項(xiàng)目合作可以私信或者郵件聯(lián)系我。
                <br/>
                點(diǎn)擊按鈕開始配網(wǎng)
            </p>
            <a href="WebConfig.html" text-decoration="none">
                <button formtarget="_self" style="display:block;margin:0 auto">
                    開始配網(wǎng)
                </button>
            </a>
        </div>
    </body>
</html>

配置網(wǎng)頁代碼:

<!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的神奇物聯(lián)網(wǎng)之旅
        </title>
    </head>
    <body>
        <div align="center">
            <font>
                IAMLIUBO
            </font>
            <br/>
            <font>
                E-mail: imliubo@makingfun.xyz
            </font>
            <br/>
            <a >
                IAMLIUBO的神奇物聯(lián)網(wǎng)之旅
            </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">
                確認(rèn)提交
            </button>
        </form>
    </body>
</html>

配網(wǎng)完成頁面:

<!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的神奇物聯(lián)網(wǎng)之旅
        </title>
    </head>
    <body>
        <div align="center">
            <font>
                IAMLIUBO
            </font>
            <br/>
            <font>
                E-mail: imliubo@makingfun.xyz
            </font>
            <br/>
            <a >
                IAMLIUBO的神奇物聯(lián)網(wǎng)之旅
            </a>
            <br/>
            <font>
                正在連接Wi-Fi锰扶,LED燈閃爍三次后連接完成献酗!
                <br/>
                常亮表示連接失敗請重新輸入!
                <br/>
                <a href="WebConfig.html" text-decoration="none">
                    <button formtarget="_self" style="display:block;margin:0 auto">
                        重新配網(wǎng)
                    </button>
                </a>
                <br/>
                <a href="/">
                    返回首頁
                </a>
            </font>
        </div>
    </body>
</html>

上個演示視頻:

https://www.bilibili.com/video/av37953711?www.bilibili.com

視頻可以去B站看了坷牛,后期比較長一點(diǎn)的視頻都會放在B站上罕偎,因?yàn)橹踝铋L可以上傳15分鐘的視頻,最大1G京闰,所以有些比較長的視頻就沒法直接上傳了颜及,請諒解,代碼稍后整理后我會上傳到我的GitHub倉蹂楣。

最后歡迎大家去我的倉庫點(diǎn)個Star俏站,您的鼓勵是我最大的動力~有問題可以私信我,或者提交issues痊土。

imliubo/makingfunxyz-esp8266?github.com


QQ交流群:592587184

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肄扎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子施戴,更是在濱河造成了極大的恐慌反浓,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赞哗,死亡現(xiàn)場離奇詭異雷则,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)肪笋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門月劈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來度迂,“玉大人,你說我怎么就攤上這事猜揪〔涯梗” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵而姐,是天一觀的道長腊凶。 經(jīng)常有香客問我,道長拴念,這世上最難降的妖魔是什么钧萍? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮政鼠,結(jié)果婚禮上风瘦,老公的妹妹穿的比我還像新娘。我一直安慰自己公般,他們只是感情好万搔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著官帘,像睡著了一般瞬雹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刽虹,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天挖炬,我揣著相機(jī)與錄音,去河邊找鬼状婶。 笑死,一個胖子當(dāng)著我的面吹牛馅巷,可吹牛的內(nèi)容都是我干的膛虫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼钓猬,長吁一口氣:“原來是場噩夢啊……” “哼稍刀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起敞曹,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤账月,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后澳迫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體局齿,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年橄登,在試婚紗的時候發(fā)現(xiàn)自己被綠了抓歼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讥此。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖谣妻,靈堂內(nèi)的尸體忽然破棺而出萄喳,到底是詐尸還是另有隱情,我是刑警寧澤蹋半,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布他巨,位于F島的核電站,受9級特大地震影響减江,放射性物質(zhì)發(fā)生泄漏染突。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一您市、第九天 我趴在偏房一處隱蔽的房頂上張望觉痛。 院中可真熱鬧,春花似錦茵休、人聲如沸薪棒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽俐芯。三九已至,卻和暖如春钉鸯,著一層夾襖步出監(jiān)牢的瞬間吧史,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工唠雕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贸营,地道東北人。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓岩睁,卻偏偏與公主長得像钞脂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子捕儒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容