1. 程式人生 > >WiFi-ESP8266入門http(3-1)網頁認證上網-post請求(原教程)

WiFi-ESP8266入門http(3-1)網頁認證上網-post請求(原教程)

nts 時空 logo 全能 targe work sig html urn

教程:http://geek-workshop.com/thread-37484-1-1.html

源碼:鏈接:https://pan.baidu.com/s/1yuYYqsM-WSOb0AbyAT0qrQ 密碼:d8e8

本帖最後由 zyzand 於 2018-5-10 16:00 編輯

前段時間,學校發了通知,說寢室要安智能電表了,由原來的每月底後付費改成預付費,說是沒余額會自動斷電,通過微信平臺查詢和繳納電費。打開查電費的界面看了一下,發現繳費的界面是需要在微信裏才能打開的,但查詢的界面能直接在普通瀏覽器打開:

<ignore_js_op>技術分享圖片


(最近剛安裝上,學校實行保電模式,所以暫時沒電費也能用哈)


正好實驗室有幾塊ESP8266和幾塊OLED。我想能不能拿ESP8266來顯示當前的實時電費信息呢?這樣就避免舍友吃雞的時候突然斷電的尷尬了。

電費信息的解析
研究了一下查詢電費的方式,發現只要更改地址就能查到不同樓層的電費信息,返回的html的源碼如下

<ignore_js_op>技術分享圖片


代碼還是比較短的,有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配置錯誤:

  1. Flash config wrong real
猜測是在編譯固件時選擇的Flash不對,我的ESP-01的flash型號是EN25Q80B-104,網上查了一下說是8Mbit(1M)的。於是在編譯時選擇Flash Size為1M(128k SPIFFS),這樣再把編譯好的固件上傳到網站上就能空中升級了。

通過杭電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請求(原教程)