前言
在我們的日常生活中,空氣品質的重要性不言而喻。尤其在都市中,空氣污染問題日益嚴重,我們需要實時監控空氣品質,以確保我們的健康。在這篇文章中,筆者將分享如何使用 Raspberry Pi Pico W 來操作空氣品質感測器,並將相關數值上傳到 Google 試算表,是一個相當簡單但是功能強大的物聯網應用喔!
筆者將會逐步介紹連接硬體、編寫軟體和解析數據的過程,讓你可以輕鬆地建立自己的空氣品質監控系統,隨時掌握周遭環境的空氣品質。
| 撰寫/攝影 | 許鈺莨 (ChatGPT協作編輯) | ||
| 時間 | 小時 | 材料表 |
|
| 難度 | 2(滿分5) | ||
本文
本專題分享如何操作 Raspberry Pi Pico W 開發板來取得空氣品質、溫溼度、PM2.5 的數值,並顯示在OLED螢幕中,最後再透過 IFTTT 將感測器數值上傳到 Google 試算表。本專題配合Thonny IDE撰寫MicroPython程式,來讀取空氣品質數值,有關於 Raspberry Pi Pico W連接Thonny IDE撰寫MicroPython程式,可以查看下段的前導文章。
前導文章
● 透過Thonny IDE撰寫
有關於Raspberry Pi Pico W透過Thonny IDE撰寫MicroPython程式,請看【使用Raspberry Pi Pico W和MicroPython進行物聯網應用開發】,文中詳細說明Raspberry Pi Pico W如何與Thonny IDE連接,並且分享了匯入感測器模組的函式庫作法。
● 雲端監測
本文使用的雲端平台是由 IFTTT 串接 Google 試算表, IFTTT 設定部分請參考【LinkIt™ 7697空氣品質偵測並上傳Google表單(空氣盒子2.0)】。
感測器接線圖
這次所使用的感測器,除沿用之前文章所說明的 PMS5003 粉塵感測器和OLED螢幕外,還用到了 SGP30 二氧化碳感測器和 DHT22 溫濕度感測器,以下說明這兩種感測器模組的線路圖。
● SGP30接線圖

● DHT22接線圖

如何查看內建函式庫
本文所需要的 python 函式庫模組,如DHT22的dht模組和雲端IFTTT時需要的requests,在Raspberry Pi Pico W中已經有內建了,需在互動環境(Shell)中輸入下列指令,可查看內建的函式庫。
[pastacode lang=”bash” manual=”help(‘modules’)” message=”” highlight=”” provider=”manual”/]撰寫程式碼
[pastacode lang=”python” manual=”import%20machine%0Aimport%20utime%0Aimport%20dht%0Afrom%20ssd1306%20import%20SSD1306_I2C%0Afrom%20adafruit_sgp30%20import%20Adafruit_SGP30%0Afrom%20time%20import%20sleep%0Aimport%20network%0Aimport%20ntptime%0Aimport%20urequests%0A%0A%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20SGP30%E5%92%8COLED%E7%9A%84I2C%0Ai2c_sgp%20%3D%20machine.SoftI2C(sda%3Dmachine.Pin(8)%2C%20scl%3Dmachine.Pin(9))%0Ai2c_oled%20%3D%20machine.SoftI2C(sda%3Dmachine.Pin(4)%2C%20scl%3Dmachine.Pin(15))%0A%0A%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20OLED%0Aoled_width%20%3D%20128%0Aoled_height%20%3D%2064%0Aoled%20%3D%20SSD1306_I2C(oled_width%2C%20oled_height%2C%20i2c_oled)%0A%0A%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20UART%0Auart%20%3D%20machine.UART(0%2C%20baudrate%3D9600%2C%20tx%3Dmachine.Pin(0)%2C%20rx%3Dmachine.Pin(1)%2C%20timeout%3D1000)%0Auart.init(9600%2C%20bits%3D8%2C%20parity%3DNone%2C%20stop%3D1)%0A%0A%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20DHT22%C2%A0%0Adht22%20%3D%20dht.DHT22(machine.Pin(2))%0A%0A%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%20SGP30%C2%A0%0Asgp30%20%3D%20Adafruit_SGP30(i2c_sgp)%0A%0A%23%20…%0A%23%20%E8%A8%AD%E7%BD%AE%E8%AE%8A%E6%95%B8%0A%23%20…%0Apm1_cf%20%3D%200%0Apm25_cf%20%3D%200%0Apm10_cf%20%3D%200%0Atemp%20%3D%200%0Ahumidity%20%3D%200%0Aeco2%20%3D%200%0Atvoc%20%3D%200%0A%0A%0A%23%20%E6%B1%BA%E5%AE%9AOLED%E5%88%87%E6%8F%9B%E9%A1%AF%E7%A4%BA%E6%84%9F%E6%B8%AC%E5%99%A8%E6%95%B8%E5%80%BC%E7%9A%84%E8%AE%8A%E6%95%B8%0Adisplay_sensor%20%3D%200%0A%0A%23%20%E7%8D%B2%E5%BE%97%E7%8F%BE%E5%9C%A8%E6%99%82%E9%96%93%0Astart_time%20%3D%20utime.time()%0A%0A%23%20%E5%88%9D%E5%A7%8B%E5%8C%96WiFi%0Asta_if%20%3D%20network.WLAN(network.STA_IF)%0Asta_if.active(True)%0A%0Awifi_ssid%20%3D%20%22XXXXXXX%22%0Awifi_password%20%3D%20%22XXXXXX%22%0A%0Asta_if.connect(wifi_ssid%2C%20wifi_password)%0A%0A%23%E8%BC%B8%E5%85%A5IFTTT%E8%B3%87%E8%A8%8A%0AIFTTT_API_KEY%20%3D%20%22XXXXXXXXXXXXX%22%0AIFTT_EVEN_NAME%3D%22XXXXXXXXXXX%22%0A%0A%0Awhile%20True%3A%0A%0A%C2%A0%20%C2%A0%20current_time%20%3D%20utime.time()%0A%0A%C2%A0%20%C2%A0%20%23%20%E5%BE%97%E5%88%B0DHT22%E6%95%B8%E5%80%BC%0A%C2%A0%20%C2%A0%20dht22.measure()%0A%C2%A0%20%C2%A0%20temp%20%3D%20dht22.temperature()%0A%C2%A0%20%C2%A0%20humidity%20%3D%20dht22.humidity()%0A%0A%C2%A0%20%C2%A0%20%23%20%E5%BE%97%E5%88%B0PMS5003%E6%95%B8%E5%80%BC%0A%C2%A0%20%C2%A0%20data%20%3D%20bytearray(uart.read(32))%0A%0A%C2%A0%20%C2%A0%20%23%20%E5%BE%97%E5%88%B0SGP30%E6%95%B8%E5%80%BC%0A%C2%A0%20%C2%A0%20eco2%20%3D%20sgp30.co2eq%0A%C2%A0%20%C2%A0%20tvoc%20%3D%20sgp30.tvoc%0A%0A%C2%A0%20%C2%A0%20if%20data%20is%20not%20None%20and%20len(data)%20%3E%3D%2010%20and%20data%5B0%5D%20%3D%3D%200×42%20and%20data%5B1%5D%20%3D%3D%200x4d%3A%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20pm1_cf%20%3D%20int.from_bytes(data%5B4%3A6%5D%2C%20’big’)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20pm25_cf%20%3D%20int.from_bytes(data%5B6%3A8%5D%2C%20’big’)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20pm10_cf%20%3D%20int.from_bytes(data%5B8%3A10%5D%2C%20’big’)%0A%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20if%20current_time%20-%20start_time%20%3E%3D%203%3A%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%23%20%E6%AF%8F3%E7%A7%92%E9%90%98%E5%88%87%E6%8F%9B%E6%95%B8%E5%80%BC%E9%A1%AF%E7%A4%BA%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20display_sensor%20%3D%20(display_sensor%20%2B%201)%20%25%203%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20start_time%20%3D%20current_time%0A%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20oled.fill(0)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20if%20display_sensor%20%3D%3D%200%3A%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%23%20%E9%A1%AF%E7%A4%BAPMS5003%E6%95%B8%E5%80%BC%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20oled.text(%22PM1.0%3A%20%25d%20ug%2Fm3%22%20%25%20pm1_cf%2C%200%2C%2022)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20oled.text(%22PM2.5%3A%20%25d%20ug%2Fm3%22%20%25%20pm25_cf%2C%200%2C%2038)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20oled.text(%22PM10%20%3A%20%25d%20ug%2Fm3%22%20%25%20pm10_cf%2C%200%2C%2054)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20elif%20display_sensor%20%3D%3D%201%3A%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%23%20%E9%A1%AF%E7%A4%BADHT22%E6%95%B8%E5%80%BC%C2%A0%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20oled.text(%22Temp%3A%20%253.1f%20C%22%20%25%20temp%2C%200%2C%2022)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20oled.text(%22Humidity%3A%20%253.1f%20%25%25%22%20%25%20humidity%2C%200%2C%2038)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20else%3A%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%23%20%E9%A1%AF%E7%A4%BASGP30%E6%95%B8%E5%80%BC%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20oled.text(%22eCO2%3A%20%25d%20ppm%22%20%25%20eco2%2C%200%2C%2022)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20oled.text(%22TVOC%3A%20%25d%20ppb%22%20%25%20tvoc%2C%200%2C%2038)%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20oled.show()%0A%0A%0A%C2%A0%20%C2%A0%20%23%20%E4%B8%8A%E5%82%B3data%20%E5%88%B0%20IFTTT%0A%C2%A0%20%C2%A0%20sensor_readings%20%3D%20%7B%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20’value1’%3A%20pm25_cf%2C%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20’value2’%3A%20temp%2C%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20’value3’%3A%20eco2%0A%C2%A0%20%C2%A0%20%7D%0A%C2%A0%20%C2%A0%20print(‘Printing%20sensorredings’)%0A%C2%A0%20%C2%A0%20print(sensor_readings)%0A%C2%A0%20%C2%A0%20request_headers%20%3D%20%7B’Content-Type’%3A%20’application%2Fjson’%7D%0A%C2%A0%20%C2%A0%C2%A0%0A%C2%A0%20%C2%A0%20request%20%3D%20urequests.post(%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20’https%3A%2F%2Fmaker.ifttt.com%2Ftrigger%2F’%20%2B%20IFTT_EVEN_NAME%20%2B’%2Fwith%2Fkey%2F’%20%2B%20IFTTT_API_KEY%2C%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20json%3Dsensor_readings%2C%0A%C2%A0%20%C2%A0%20%C2%A0%20%C2%A0%20headers%3Drequest_headers%0A%C2%A0%20%C2%A0%20)%0A%C2%A0%20%C2%A0%20print(request.text)%0A%C2%A0%20%C2%A0%20request.close()%0A%C2%A0%20%C2%A0%C2%A0%0A%C2%A0%20%C2%A0%20sleep(1)” message=”PMS5003_DHT22_SGP30_IFTTT.py” highlight=”” provider=”manual”/]如何自動執行程式
如果希望自動執行程式,只需要將上述程式碼檔名改成 main.py 之後存入 Raspberry Pi Pico W中即可,說明如下。
開啟檔案>另存新檔

選Raspberry Pi Pico>將檔案名稱改成”main.py”


執行結果
執行程式之後,就會在 Thonny IDE 中看到相關訊息,開啟對應的 Google 試算表之後也會看到數值一筆筆進來了。
如果無法順利執行程式,請檢查先前所有設定與感測器接線,預祝成功囉!







