一般雲端平台除了可以用我們先前提到的 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 的差別:
- GET:就是將請求動作的相關訊息的都內含在 url 網址內完成,舉例來說,如果要想要查詢台北的天氣,各位可以連上 https://www.accuweather.com/en/tw/taiwan-weather 這個網址,並在搜尋欄內打入 taipei 字樣,會發現出來的網址就是 https://www.accuweather.com/en/search-locations?query=taipei。後面的 query 是查詢的意思,?query=taipei 就是將想要做的查詢動作直接包含在網址內。
- 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,後續在才可以填入我們的程式內,官方也有提供的一個範例參考:
這邊的範例就是採用 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 <–得到最新文章通知