ESP32 教學 | MicroPython | 使用 ThingSpeak HTTP API 上傳 DHT11 資訊 | 305

一般雲端平台除了可以用我們先前提到的 mqtt 協定上傳資料,通常也可以用 http 協定上傳或讀取資料,今天這篇分享如何使用 micropython 內建的 HTTP 請求 urequests 模組,結合 Thingspeak Http API 方法來上傳 DHT11 的溫濕度資料。

Tips:  如果對 DHT11 或 Thingspeak 帳號申請與上傳不是很瞭解的朋友,可以參考JIMI哥之前的寫的這幾篇:

1. HTTP 基本概念

HTTP ( Hypertext Transfer Protocol )是一種針對網頁為主的網路協定,是建構在 TCP 通訊上的資料傳輸方法,概念跟先前提到 MQTT 類似,一樣屬為用戶端 Client 與伺服器 Server 架構。Client 與 Server 在建立起 TCP 連線後,提出 Request 訊息請求到伺服器,伺服器收到後做出 Response 訊息回應,結束完成後斷開 TCP 連線。

>> HTTP Request 訊息

HTTP 訊息採用一個標準的規範(不管是 Request 或 Response ),主要組成都包含 start-line(status-line)、Header 跟 Body,我們先來看一下 HTTP Request 部分: (這個封包是透過火狐瀏覽器連上 www.yahoo.com.tw 的過程中所擷取的)

在 Request 訊息內,start-line 就會包含所謂的 http方法請求目標http版本。『http方法 』有很多種,像是常用的 GET 或 POST, 請求目標就是會放入 url 網址(這邊的 / 就是指主機的網頁根目錄 ),這邊來簡單介紹一下 GET 跟 POST 的差別:

  • POST:與 GET 方法最大的差異就就是把一些請求動作的指示或內容,放在 HTTP Request 訊息的 Body 區,所以特色為可以傳送大量的資料。

至於 Request 訊息的 Header 區塊,就會放入包含要連線的主機名稱、瀏覽器種類、文字編碼等資料。

最後則是訊息主體 (Body) 的部分,內容會放入欲傳達的資料,這邊有個觀念提一下,不是所有的 Http Request 都會有 Body 的訊息內容,像是如果用 GET 方法來處理的話,大部分是不需要的。

>> HTTP Response 訊息

下面的訊息為一個實際 Http Response 的訊息:(擷取來自 yahoo 主機回應至電腦瀏覽器用戶端封包 )

Status-Line 狀態列會有三個部分:http版本、狀態碼、狀態文字。狀態碼就是我們常看到的 200、301、400 等,表示伺服器端對用戶端的請求回應,狀態文字就是解釋狀態碼的敘述,各位朋友僅需要知道這幾個常用的就可以了 :

  • 200 –>連線OK
  • 301–> 連線的位址被移動
  • 401–> 未認證、登入失敗
  • 404–> 找不到網頁

Response 訊息的 Header 內容會有伺服器種類、 內容形式與長度、cookie、Location 等。

最後的訊息主體(Body)如果是用戶端的請求是下載網頁, 就會將網頁(html/javascript/css)的內容放入,最後傳到用戶端的瀏覽器去呈現最後的網頁結果。

2. Micropython urequests 模組

有了 Http 通訊的基本概念後,就可以開始瞭解如何使用 ESP32 進行 Http/Https 請求。關於這個部分,micropython 有幾個模組都可以實現,JIMI哥 建議各位如果要用的話,可以直接使用內建的 urequests 模組,這個模組其實是由電腦版 Python requests 模組實現而來,但畢竟嵌入式平台的硬體還是有限制,所以並沒有完全移植,但建立各種基本 http 請求已經夠用,下面為 urequests 的 GET 與 POST 使用範例:

import urequests
response1= urequests.get(url)
response2= urequests.post(url,data=msg0)

第 2 行urequests.get(url)就是提出 http GET 請求,url 就是放入傳遞的網址;第 3 行urequests.post(url,data=msg0) 為 http POST 請求,data 為欲傳遞的訊息主體(body),也可以看到 GET 與 POST 方法的差別。

如果各位有用過其他的網路模組( usocket 等),在發送 http-request 請求時,很多時候自己得去把 start-line 跟 header 的樣式填入程式碼內,像下面文字樣式:

POST /update HTTP/1.1
Host: api.thingspeak.com
Connection: close
X-THINGSPEAKAPIKEY:  xxxxxxxxxx
Content-Type: application/x-www-form-urlencoded
Content-Length: xxxxx

urequests 其實就是把上述這些格式與協定『包裝』起來,使用者只要填入關鍵內容(網址或訊息主體),其他東西這個模組就可以幫你搞定。當然除了GET 跟 POST 方法外,urequests 也可以使用 DELETE、HEAD、PUT等方法,端看自己的應用環境。

而在用戶端丟出請求後,伺服器會傳出 http 回應,urequest 模組會將其回應變成一個 response 物件(也就是程式中的 response1 或 response2),可以進行的操作有:

  • response.text : 為伺服器回應的內容,字串 string 型別,所以可以用 print 方式顯示。
  • response.status_code:這邊會儲存狀態碼(200、404等),很多時候我們可以在程式內透過此數值來判斷 http 請求的狀態,做出重新請求或其他動作。
  • response.json():此方法將伺服器回應的內容轉成 dict 格式儲存(前提是回應內容為 json 格式),應用在下載開放資訊時的資料處理。

3. 使用 ThingSpeak HTTP API 上傳 DHT11 感測資料

基本Http概念都知道後,就可以來準備上傳 DHT11 資料到Thingspeak 雲端,因為此次是要用 https 的方式上傳資料,我們先登入 thingspeak,按下 api_key 的標籤,找到 Write_API_Key,後續在才可以填入我們的程式內,官方也有提供的一個範例參考:

thingspeak http

這邊的範例就是採用 HTTP GET 請求方法,而網址格式如下:

https://api.thingspeak.com/update?api_key=JROXXXXXXXXXXXX&field1=XX

api_key 就是填入自己專屬的編碼,field1的值就是你想上傳的數值,不同的參數用&符號連接,所以如果三個數值(欄位)想要上傳,就可以將網址填入field1=xx&field2=xx&field3=xx,依此類推,當然有幾個欄位(field)啟用是在官網的設定介面中去修改的。

>> 電路連接

電路連接方法與 MQTT 版本一樣,DTH11 的資料線與 ESP32 GPIO14連接,其他連接 3.3V 與 GND。

>> 完整程式碼

import machine,dht,utime,time,network,urequests

def go_wifi():
    try:
        wifi.active(False)
        wifi.active(True)
        wifi.connect('tp_station','0000xxxx')
        print('start to connect wifi')
        for i in range(20):
            print('try to connect wifi in {}s'.format(i))
            utime.sleep(1)
            if wifi.isconnected():
                break          
        if wifi.isconnected():
            print('WiFi connection OK!')
            print('Network Config=',wifi.ifconfig())
        else:
            print('WiFi connection Error') 
    except Exception as e: print(e)
        
d11=dht.DHT11(machine.Pin(14))      # GPIO14 as the DHT11 dataline
w_api='JROxxxxxxxxxxxx'			    # thingspeak write api key
wifi= network.WLAN(network.STA_IF)
go_wifi()
while 1:
    d11.measure()
    thing_url='https://api.thingspeak.com/update?api_key={}&field1={}&field2={}'.format(w_api,d11.temperature(),d11.humidity())
    try:
        thing_response= urequests.get(thing_url)
        print('code={},content=  {}'.format(thing_response.status_code,thing_response.text))
    except Exception as e: 
        print(e)
        go_wifi()  
    thing_response.close()
    time.sleep(15)

>> 程式解說

import machine,dht,utime,time,network,urequests

def go_wifi():
    try:
        wifi.active(False)
        wifi.active(True)
        wifi.connect('tp_station','0000xxxx')
        print('start to connect wifi')
        for i in range(20):
            print('try to connect wifi in {}s'.format(i))
            utime.sleep(1)
            if wifi.isconnected():
                break          
        if wifi.isconnected():
            print('WiFi connection OK!')
            print('Network Config=',wifi.ifconfig())
        else:
            print('WiFi connection Error') 
    except Exception as e: print(e)
        
d11=dht.DHT11(machine.Pin(14))      # GPIO14 as the DHT11 dataline
w_api='JROxxxxxxxxxxxx'			    # thingspeak write api key
wifi= network.WLAN(network.STA_IF)

首先匯入所需的模組,這邊先將連網動作寫成一個名稱 go_wifi()的函式,如後續程序連線異常時,方便呼叫使用。接著建立 DHT11與 wifi 物件,同時設定 write_api_key 的參數。(這邊 api_key 要改成自己的專屬碼)

go_wifi()
while 1:
    d11.measure()
    thing_url='https://api.thingspeak.com/update?api_key={}&field1={}&field2={}'.format(w_api,d11.temperature(),d11.humidity())

由於 urequest 模組在使用前,必須先將 ESP32 透過 wifi 連網,因此先執行 go_wifi() 函式連網。接著 while 迴圈內,將 DHT11 溫濕度值取出,建置 thingspeak GET 規定的網址格式,溫度與濕度在 thingspeak channel 分別設定於 field1 與 field2,將 api_key 與 fields 數值連接就是 api_key={ }&field1={ }&field2={ }。

 try:
        thing_response= urequests.get(thing_url)
        print('code={},content=  {}'.format(thing_response.status_code,thing_response.text))
    except Exception as e: 
        print(e)
        go_wifi()  
    thing_response.close()
    time.sleep(15)

這段程式碼開始送出 Http 的 Request,方法採用 GET,將 write_api_key 與其他參數包入網址送出,順便將StatusCode 狀態碼與 thingspeak 伺服器回覆內容輸出到螢幕上。

這邊特別解釋一下什麼要用 try-except 做異常處理,因為 urequests 模組連線 api thingspeak 主機時,有時會突然發生系統異常(OsError 202),查詢網路資料推測應該是與 SSL 認證相關,為確保能持續更新資料,程序上就寫成如有任何異常,wifi 重新連線,這樣就可以避免偶發性的資料中斷。

thing_response.close() ,這個強烈建議在每次執行完 htttp request 後就放入來關閉 http連線,因為 SSL 證非常耗費 ESP32 的記憶體,JIMI哥 自己的經驗是如果沒有加上的話,大約上傳2-3次就會出現系統錯誤 OsError ENOMEM。

最後的 time.sleep(15) 是因為 thingspeak 免費帳號的限制為 15 秒一次資料,在每次成功上傳後,控制器便休息設定的時間,結束後再次執行 http 與 DHT11相關程序。

4. 總結

本篇主要以 HTTP GET的方法,搭配 micropython 的 urequests 模組上傳 DHT11感測資料到 thingspeak 雲端,如果應用情境不允許使用 GET 網址傳送參數時,其實改用 api_key 與訊息都放入 ruequests 主體的 POST方法,也都可以順利上傳 thingspeak,就看各位喜歡哪種方式囉!

今天的內容就到這邊,如果各位有遇到什麼問題或想看那些教學內容,也歡迎在下面留言或寫信與我討論囉~

↓↓↓↓↓↓賣場連結↓↓↓↓↓↓

歡迎大家有需要的話,可以多多支持一下我們的蝦皮賣場喔! 😀 

吉米家官方店-創客機器人材料專賣 https://shopee.tw/jimirobot.tw

Follow JIMI哥 Twitter : https://twitter.com/jimirobot  <–得到最新文章通知

發佈留言

Close Menu