WiFi-ESP8266入門http(3-1)網頁認證上網-post請求(原教程)
教程:http://geek-workshop.com/thread-37484-1-1.html
源碼:鏈接:https://pan.baidu.com/s/1yuYYqsM-WSOb0AbyAT0qrQ 密碼:d8e8
本帖最後由 zyzand 於 2018-5-10 16:00 編輯
前段時間,學校發了通知,說寢室要安智能電表了,由原來的每月底後付費改成預付費,說是沒余額會自動斷電,通過微信平臺查詢和繳納電費。打開查電費的界面看了一下,發現繳費的界面是需要在微信裏才能打開的,但查詢的界面能直接在普通瀏覽器打開:
![技術分享圖片](http://image.geek-workshop.com/forum/201805/06/124036wkrd122hac2u3pdd.png)
(最近剛安裝上,學校實行保電模式,所以暫時沒電費也能用哈)
正好實驗室有幾塊ESP8266和幾塊OLED。我想能不能拿ESP8266來顯示當前的實時電費信息呢?這樣就避免舍友吃雞的時候突然斷電的尷尬了。
電費信息的解析
研究了一下查詢電費的方式,發現只要更改地址就能查到不同樓層的電費信息,返回的html的源碼如下
![技術分享圖片](http://image.geek-workshop.com/forum/201805/06/124036i7i7djc8ei961yfi.png)
代碼還是比較短的,有1M內存的ESP8266完全能應付得來。
思路也很簡單,就只先用http庫獲取到網頁源碼,然後使用關鍵信息前後的字符截取出相應的信息。解析信息的方法如下。(代碼可能寫的不太規範,歡迎大神指點)
struct priceinf { float price; char timestr[20 * 7]; int year; int month; int day; int hh; int mm; int ss; char lou[20]; char qinshi[10]; }; /* 返回信息解析 傳入:html代碼 返回:解析出來的信息(priceinf 結構體) 未解析到則返回空的結構體 */ priceinf getPrice(String s) { priceinf dat; int datStart = 0, datEnd = 0; String datstr; char buf[50]; char datsign[] = "<span class=\"price\""; datStart = s.indexOf(datsign) + strlen(datsign) + 23; if (datStart == strlen(datsign) + 23 - 1) { //沒有找到price memset(&dat, 0, sizeof(dat)); return dat; } datEnd = s.indexOf("</span>", datStart) - 2; //減2是為了減去字符“元” datstr = s.substring(datStart, datEnd); dat.price = datstr.toFloat(); char timesign[] = "<font style=\"color:#2d9fd3\"><b>"; datStart = s.indexOf(timesign) + strlen(timesign); datEnd = s.indexOf("</b></font>", datStart); //結尾 datstr = s.substring(datStart, datEnd); datstr.toCharArray(dat.timestr, 20); dat.timestr[19] = 0; dat.year = datstr.substring(0, 4).toInt(); dat.month = datstr.substring(5, 7).toInt(); dat.day = datstr.substring(8, 10).toInt(); dat.hh = datstr.substring(11, 13).toInt(); dat.mm = datstr.substring(14, 16).toInt(); dat.ss = datstr.substring(17, 19).toInt(); char lousign[] = "樓幢:"; datStart = s.indexOf(lousign) + strlen(lousign); datEnd = s.indexOf("</p>", datStart); //結尾 datstr = s.substring(datStart, datEnd); datstr.toCharArray(dat.lou, 20); dat.lou[19] = 0; char qinshisign[] = "寢室號:"; datStart = s.indexOf(qinshisign) + strlen(qinshisign); datEnd = s.indexOf("</p>", datStart); //結尾 datstr = s.substring(datStart, datEnd); datstr.toCharArray(dat.qinshi, 10); dat.qinshi[9] = 0; //Serial.println(s); Serial.print("time="); Serial.println(dat.timestr); Serial.print("price="); Serial.println(dat.price); Serial.print("lou="); Serial.println(dat.lou); Serial.print("qinshi="); Serial.println(dat.qinshi); Serial.println(); return dat; }
這個函數能實現對截止時間,樓,寢室號,剩余電費的解析,並把解析到的信息儲存在結構體裏。
然後把信息用OLED顯示出來,不過這塊OLED默認是SPI的,而我用的ESP-01最多只有3個能自定義的io,完全不夠用。所以要改成IIC接口。按照說明改一下背後的電阻,然後將RES接VCC,CS、DC接GND,這樣D0就是SCL,D1是SDA了。分別連接到ESP8266的GPOP0和GPIO2上。
把OLED 屏幕的軟件IIC庫導入到Arduino裏,測試一下還挺好用。
其他功能
到這裏這個程序就基本完成了,難度不是很大。但感覺這個程序好簡單啊,ESP8266的潛能還沒全發揮出來,於是,當做練習,在這個程序裏加入了SmartConfig,用來應對應對沒有已知密碼的wifi的情況,然後讓他能開機時從指定網址先獲取查詢電費的網址,並能從指定網址進行OTA空中升級。這樣就不止能查詢自己的宿舍,並且就算送給別人用也能隨時對程序進行修改。
獲取查詢網址和升級信息的函數,為了方便可管理多個終端,在開機的時候會先獲取本芯片的唯一SN號,然後程序會訪問自己SN號對應的網址,這樣就不用為每一個芯片單獨燒寫固件了,同一個固件就能去訪問不同的網址:
int site_Get() { int ret = 0; if ((WiFiMulti.run() == WL_CONNECTED)) { HTTPClient http; Serial.printf("[www.zyzand.com]Connect to www.zyzand.com...\n"); http.begin("www.zyzand.com", 80, (String)"/IoT/clients/" + SN + "/index.php"); //HTTP int httpCode = http.GET(); int i = 5;//重試次數 while (i-- > 0 && httpCode != 200) { Serial.printf("[www.zyzand.com]code: %d Try again...", httpCode); delay(1000); httpCode = http.GET(); } //從www.zyzand.com獲取信息失敗 if (httpCode != 200) { Serial.printf("[www.zyzand.com] GET Fail!"); ret = 2; } //成功則進行數據解析 else { Serial.println("[www.zyzand.com]GET data:"); String payload = http.getString(); Serial.println(payload); int nflag = payload.indexOf("\n"); Serial.println(nflag); Serial.println(payload.indexOf("\n", nflag)); dat1 = payload.substring(0, nflag); dat2 = payload.substring(nflag + 1, payload.indexOf("\n", nflag + 1)); Serial.print("[www.zyzand.com]dat1 = "); Serial.println(dat1); Serial.print("[www.zyzand.com]dat2 = "); Serial.println(dat2); //OTA if (strcmp(dat1.c_str(), "updata") == 0) { OTA(); } } } else {//WiFi連接失敗 Serial.print("[www.zyzand.com]WiFi failed\n"); ret = 1; } //失敗時的處理 if (ret != 0) { dat1 = "zyzand.com"; dat2 = (String)"/IoT/clients/" + SN + "/error/index.php"; } return ret; }
在測試OTA空中升級的時候,遇到的問題值得提一下。開始時空中升級總是返回flash配置錯誤:
- Flash config wrong real
通過杭電i-hdu上網認證
我所在的學校有校園免費wifi,連接是不需要密碼的,但是連接後會自動跳轉到一個網頁,需要進行認證才能訪問外網。一直對他的認證方法感興趣,於是用Fiddler抓了一下包,發現用來認證信息的只是一個post請求,也不是很復雜。在電腦上模擬成功,用ESP8266試了一下,也成功通過。
/* 通過i-HDU認證,請自己修改postDate中的學號和密碼 */ int hdulogin() { const char * host = "2.2.2.2"; const int httpPort = 80; WiFiClient client; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); return 1; } delay(10); String postDate = "opr=pwdLogin&userName=你的學號&pwd=學號對應的密碼&rememberPwd=1";//將從串口接收的數據發送到服務器,readLine()方法可以自行設計 if (postDate.length() && postDate != "0") { String data = (String)postDate; int length = data.length(); String postRequest = (String)("POST ") + "/ac_portal/login.php HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: Keep Alive\r\n" + "Content-Length: " + length + "\r\n" + "Accept: */*\r\n" + "Origin: http://2.2.2.2\r\n" + "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" + "\r\n" + "User-Agent: zyzandESP8266\r\n" + "\r\n" + data + "\r\n"; //Serial.println(postRequest); Serial.println(); client.print(postRequest); delay(600); //處理返回信息 String line = client.readStringUntil(‘\n‘); while (client.available() > 0) { line += client.readStringUntil(‘\n‘); } // Serial.println(line); client.stop(); if (line.indexOf("logon success") != -1 || line.indexOf("不需要") != -1) { //認證成功 return 0; } else { return 2; } } }
最後自己焊接了個小板子,用AMS1117-3.3進行降壓:
<ignore_js_op>
<ignore_js_op>
WiFi-ESP8266入門http(3-1)網頁認證上網-post請求(原教程)