2014年5月15日 星期四

用Arduino讀取網頁資訊 - 原理解釋

使用Arduino加上Spider L3S的WiFi模組就可以將網頁的資訊給擷取下來,但是到底是如何做到的呢? 此篇就來解釋運作的原理。




首先,我們要先了解http連線的原理



Http協定是透過TCP連線,將伺服器與瀏覽器連接起來後,再透過連接起的連線跑Http的傳輸協定語法。所以我只要讓Spider L3S透過TCP客戶端對網頁伺服器連線,並且送出對應的HTTP 訊息就可以取得網頁。

整體的程式架構流程是這樣的


範例程式可以從Github取得

首先,先修改SSID與密碼,程式會在setup內Initial Spider L3S,讓Spider L3S連接上WiFi AP
/* Initial Spider L3 */
    Serial.print(F("Starting Spider L3..."));
    ret = Spider_begin();
    if(ret != 0){
        Serial.println(F("fail, please check connection pin."));
        while(1) ;
    }
    Serial.println(F("ok"));

    /* Connect to WiFi AP */
    Serial.print(F("Connect to "));
    Serial.write((unsigned char*)AP_Ssid, strlen(AP_Ssid));
    Serial.print(F(" access point..."));
    ret = Spider_Connect(3, (char*)AP_Ssid, (char*)AP_Pass);
    if(ret != 0){
        Serial.println(F("fail."));
        while(1) ;
    }
    Serial.println(F("ok"));
// Don't forget set correct WiFi SSID and Password.
char AP_Ssid[] = {"xxxxxxxx"};
char AP_Pass[] = {"xxxxxxxx"};

待Initial完成後,便開始執行loop內的程式擷取Yahoo weather RSS網頁。

我將擷取網頁的過程分為幾個步驟:

1.取得Yahoo server的IP address

透過WebClient_Get_HostIP這函式,分析api_url_link內的網址,取得Server的IP位址
/* Target URL link */
char api_url_link[] = {"http://weather.yahooapis.com/forecastrss?w=2306179&u=c"};
ret = WebClient_Get_HostIP(api_url_link, &ip[0], &ip[1], &ip[2], &ip[3]);

2.設定TCP連線

設定TCP連線,目的為剛剛取得的IP位址,Port為80
ret = WebClient_Begin_IP(&host_inf, ip[0],  ip[1],  ip[2],  ip[3], 80);

3.連上Yahoo server
ret = WebClient_Connect(&host_inf);

4.送出http request
ret = WebClient_SendRequest(&host_inf, api_url_link);

5.接收網頁
ret = WebClient_RecvData(&host_inf, ret_data, sizeof(ret_data));

6.分析資料

這階段其實分為兩個步驟,首先可以先看要抓取網頁的原始碼,並查看網頁原始碼,可以看到一堆氣象溫度資訊用XML格式顯示出來。

目前台北市內湖的氣象資訊是這一行
 yweather:condition code="11" date="Thu, 15 May 2014 11:30 am CST" temp="29" text="Light Rain">

所以我對網頁資料做分析,將temp="?"的資訊抓取出來
/* Do information parsing */
char* str1;
str1 = strstr(ret_data, "temp=\"");
if(str1 != 0){
    digitalWrite(INDICATE_LED, HIGH);
                                
    char* str2 = 0;
    int temp = 0;
 
    str1 += strlen("temp=\"");
    str2 = strstr(str1, "\"");
    *str2 = 0;
    sscanf(str1, "%d", &temp);

    /* Print tempecture */
    Serial.print(F("Tempecture of Taipei city:"));
    Serial.print(temp, DEC);
    Serial.println();
    digitalWrite(INDICATE_LED, LOW);
}

並透過Serial Monitor傳出來

這樣就完成了,有沒有很簡單啊?

但是這方法目前只適用於一些稍微簡單的網頁,或者雲端業者提供的雲端API網頁讀取資料,如果較複雜(ex. Flash, 帳號登入等)就比較不適用。不過我相信未來這邊的資訊取的會越來越便利與簡單,也可以創造出更多嶄新的應用,讓虛擬資訊也能夠實體化與人們產生互動。

14 則留言:

  1. 請問 透過WIFI在進行控制時
    是不是只能透過網頁的方式做到?

    然後WIFI有辦法傳輸影像或是語音這方面的數據呢?

    回覆刪除
  2. Hi方先生:

    1.可透過網頁外的方式控制,如TCP或者UDP。目前我們用網頁的原因是因為跨平台(PC、Apple、Android),不用在每個平台都為我們的範例程式寫一個APP。

    2.只要頻寬夠用(註1.)可以傳輸影像或者語音,但是需要注意到頻寬問題。目前有在非Arduino平台上成功串流192Kbps的網路電台。

    註1. 在TI討論區有官方FAE回答頻寬問題,約4Mbps http://e2e.ti.com/support/wireless_connectivity/f/851/t/273104.aspx

    回覆刪除
  3. 回覆
    1. 那個是return data的縮寫,是接收資料用的buffer。

      刪除
  4. 作者已經移除這則留言。

    回覆刪除
  5. 請問一下 WIFI板子上的腳位可以自行更改嗎 ?
    因為我想利用WIFI和RFID結合
    但程式燒好後 始終只會執行WIFI板子的結果 但RFID都沒反應
    所以想說 會是因為兩個腳位都會重複到11 12 13的關係嗎 ?

    回覆刪除
    回覆
    1. 11 12 13是SPI接腳,理論上可以共用,但是實際上會牽扯到Driver層與CS腳切換的問題,尤其WiFi的Driver是使用外部中斷觸發SPI接收資料的,可能會在你傳送接收RFID資料時搶走SPI資源,導製RFID那邊資料錯亂。

      建議你了解一下SPI接腳共用的一些資訊,再研究一下Driver要如何修改,或者將WiFi / RFID其中一個改為軟體SPI。

      刪除
  6. 我將SPIDER WIFI板子的腳位保持不變
    再把RFID的腳位 11 12 13 改成ICSP-4 、ICSP-1和ICSP-3
    但程式RUN到讀取RFID的地方 依然不能

    回覆刪除
    回覆
    1. 你可以參考一下Arduino官方對於各板子的SPI接腳定義
      http://arduino.cc/en/Reference/SPI

      如果是Uno的話...換腳位其實沒有差別,因為會是同一隻腳,你的問題比較像是SPI資源互相搶到的問題。

      刪除
  7. 恩恩 謝謝你
    我大概知道問題所在了
    那再請問一下 這個spider wifi板上的CS是指SPI上的SS嗎 ?

    回覆刪除
    回覆
    1. 不是喔,CS腳位設定是由Arduino內的程式設定的。

      刪除
  8. 請問一下,
    如果今天是用ethernet shield這塊擴充板
    我想單純設定TCP的方式傳送跟接收封包
    請問有相關的函式或sample可以參考嗎?

    回覆刪除
    回覆
    1. 沒有,但是原理都相同,在此我是用bsd socket的style去寫出來的。

      刪除
  9. 請問是否適用於抓取空污指數網頁
    http://taqm.epa.gov.tw/taqm/tw/default.aspx
    擷取後LED依照
    選定檢測站之指數燈顏色顯示?
    謝謝指導~

    回覆刪除