2024年10月5日 星期六

MicroPython 學習筆記 : 串接物聯網雲端平台 ThingSpeak (三)

在前一篇測試中我們使用 HTTP GET 方法, 利用 urequests.get() 呼叫 ThingSpeak API 將氣象資料傳送到 ThingSpeak 通道資料表中儲存, 本篇則是要改用 POST 方法, 順便測試原 xtools 函式庫中的 webhook.post() 函式, 它原本是呼叫 xrequests.post(), 但我將其改為 urequests.post(), 如果沒問題就可以拿掉 xrequests.py 了. 


以下實驗是在燒錄 MicroPython v1.23 版韌體的 ESP32-WROOM 開發板上進行. 為了不干擾前一篇實驗的運作, 這次改用 Gmail 申請的 ThingSpeak 帳號來測試, 建立了一個 '高雄的天氣2' 通道, 同樣有 field1 (溫度), field2 (濕度), 與 field3 (氣壓) 三個欄位 : 




點選 API key 頁籤將 WRITE API key 記下來備用 (存入 config.py). 


5. 使用 HTTP POST 方法呼叫 ThingSpeak API : 

先匯入 config 與 xtools 模組呼叫 xtools.coneect_wifi() 連上網路 : 

>>> import xtools   
>>> import config    
>>> ip=xtools.connect_wifi(config.SSID, config.PASSWORD)  
network config: ('192.168.50.9', '255.255.255.0', '192.168.50.1', '192.168.50.1')
'192.168.50.9'

我已經將 ThingSpeak 的通道寫入 API key 儲存於 config.py 的 THINGSPEAK_API_KEY 字串變數中, 只要將其取出即可 :

>>> thingspeak_api_key=config.THINGSPEAK_API_KEY   

接著製作 POST 方法要傳送的資料字典, 將 API key 放入 api_key 鍵, 欄位資料分別放入 filed1~filed8 鍵 :

>>> data={
    'api_key': thingspeak_api_key,
    'field1': 27,
    'field2': 87,
    'field3': 980
    }

在 CPython 中可以在呼叫 requests.post() 時將字典直接傳給 data 參數, 但在 MicroPython 不能這麼做, 因為 MicroPython 的 urequests 模組要求傳給 post() 函式的 data 參數必須是字串或 bytes 類型, 故此處須先呼叫 xtools 的 urlencode() 函式先將 data 字典轉成 URL 字串, 然後呼叫 encode() 以 utf-8 格式把 URL 字串編碼為 bytes 類型資料 : 

>>> payload=xtools.urlencode(data).encode('utf-8')      

這樣就可以匯入 urequests 呼叫其 post() 方法將編碼後的 payload 傳給 data 參數, ThingSpeak 的 POST API 網址如下 :

# https://api.thingspeak.com/update 

>>> import urequests     
>>> url='https://api.thingspeak.com/update'    
>>> r=urequests.post(url, data=payload)    
>>> r.text       
'1'

傳回數值表示請求成功, 1 表示這是向 ThingSpeak 傳送的第一則訊息, 免費帳戶一年內有 300 萬則訊息額度可用. 這時 Dashbord 會在欄位的折線圖上顯示這個數據 :




改用 xtools 的 webhook_post(url, value) 也是可以的, 只要將編碼過的 payload 傳給它的第二參數 value 即可 : 

>>> r=xtools.webhook_post(url, payload)   
invoking webhook
Webhook invoked
>>> r.text    
'2'

傳回 2 表示第二則訊息也傳成功了, 這時 Dashboard 上會顯示兩個相同值的點 : 




注意, xtools 中的 webhook_post() 原本是呼叫原作者自訂 xrequests 模組的 post(), 我已將其改為 MicroPython 內建的 urequests,post() 且傳回回應值 r : 

def webhook_post(url, value):
    print("invoking webhook")
    r = urequests.post(url, data=value)
    if r is not None and r.status_code == 200:
        print("Webhook invoked")
    else:
        print("Webhook failed")
        show_error()
    return r

以上測試確認 webhook_post() 改用 urequests.post() 沒有問題, 應此在新版 xtools 函式庫中我已移除 xrequests.py 這個檔案, 且 xtools.py 中取消匯入 xrequests.py. 

我將上一篇的 weather_app.py 改成如下的 POST 版 : 

# weather_app.py
import xtools    
import config
import time
import urequests
import ujson

def get_weather_now(country, city, api_key):
    url=f'https://api.openweathermap.org/data/2.5/weather?q={city},{country}&units=metric&lang=zh_tw&appid={api_key}'
    try:
        res=urequests.get(url)
        data=ujson.loads(res.text)
        if data['cod']==200:    # 注意是數值
            ret={'geocode': data['id'],
                 'description': data['weather'][0]['description'],
                 'temperature': data['main']['temp'],
                 'min_temperature': data['main']['temp_min'], 
                 'max_temperature': data['main']['temp_max'],
                 'pressure': data['main']['pressure'],
                 'humidity': data['main']['humidity']}
            return ret
        else:
            return None
    except Exception as e:
        return None

def main():
    thingspeak_api_key=config.THINGSPEAK_WRITE_API_KEY   
    weather_api_key=config.WEATHER_API_KEY      
    city='Kaohsiung'     
    country='TW'    
    while True:
        r=get_weather_now(country, city, weather_api_key)
        if r != None:
            temperature=r['temperature']
            humidity=r['humidity']
            pressure=r['pressure']
            url=f'https://api.thingspeak.com/update'
            data={
                'api_key': thingspeak_api_key,
                'field1': temperature,
                'field2': humidity,
                'field3': pressure
                }
            payload=xtools.urlencode(data).encode('utf-8')
            r=urequests.post(url, data=payload)
            print(r.text)
            time.sleep(15)
        else:
            print('Fail to get weather data.')

if __name__ == '__main__':  
    main()  
      
修改之處為藍色粗體部分, 將程式上傳後按 Reset 鈕重啟系統, 就可看到新帳號上的 '高雄的天氣2' 通道每 15 秒更新的氣象資料統計圖 : 




開啟 Sharing 為 "Share chnnel view with everyone" :


不過此通道只是測試 POST 用, 跑一個下午後就會關掉了. 

沒有留言 :