IOT物聯網Raspberry Pi Pico W 智慧淹水偵測系統,結合 Google 試算表與 LINE 通訊軟體
前言
本篇文章要來介紹的是使用 Raspberry Pico W 和 RS485 溫溼度感測器的淹水偵測裝置,為了因應最近強降雨的情形,怕地下室淹水所製作的,現在這套設備正在 CAVEDU 地下室服役中。
Pico W淹水偵測裝置功能如下:
➡️每15分鐘會上傳資料點至Google Sheet雲端,以確保裝置運作中
➡️可定時(如:每日7:00PM把目前偵測到的溫溼度發送到 LINE 通訊軟體
➡️若濕度過高,則會立即通報LINE中。由於LINE可以把相關人員加入群組中,所以只要有人接到通報,就可以第一時間做處置。
https://youtu.be/hDFx26F5vZ8
| 撰寫/攝影 |
許鈺莨 (ChatGPT協作編輯) |
| 時間 |
2 小時 |
材料表 |
|
| 難度 |
2(滿分5) |
本文
智慧偵測淹水裝置接線圖
智慧偵測淹水裝置主要由下列元件所組成:
- Raspberry Pi Pico W: 接收RS485感測器訊號,並上傳至雲端及LINE 訊息。
- Raspberry Pi Pico W擴充板 : 擴充Raspberry Pi Pico W腳位,以方便將感測器腳位。
- TTL轉RS485模組 : 可將RS485感測器訊號轉成TTL訊號,再讓Raspberry Pi Pico W接收
- RS485溫溼度感測器:可以偵測室內的溫度及濕度。
- LCD液晶螢幕: 主要顯示目前的溼度狀況與時間。
- Raspberry Pi Pico W擴充板與LCD 接線
- Raspberry Pi Pico W擴充板與TTL轉RS485模組接線
- TTL轉RS485模組接線與RS485溫濕度感測器接線
智慧偵測淹水裝置流程圖
系統流程圖如下 (點選看大圖)
智慧偵測淹水裝置匯入LCD函式庫
- 匯入 Raspberry Pi pico 函式庫的做法,請參考「使用 Raspberry Pi Pico W 和 MicroPython 開發物聯網應用」
- 函式庫下載:https://reurl.cc/Dov54e
- 匯入檔案指令,匯入以上連結下載的 lcd_api.py 和 i2c_lcd.py
[pastacode lang="bash" manual="cd%20LCD_library%0Aampy%20--port%20COMX%20put%20lcd_api.py%0Aampy%20--port%20COMX%20put%20i2c_lcd.py" message="" highlight="" provider="manual"/]
- 智慧偵測淹水裝置程式全貌
下列程式中需要 IFTTT 作為中介軟體來串接 pico W 與 LINE,相關IFTTT申請步驟,請參考 「
LinkIt™ 7697空氣品質偵測並上傳Google表單(空氣盒子2.0)」。,並將申請到的 IFTTT 相關資訊填入以下 .py 檔之後上傳到 pi pico 開發板即可。
[pastacode lang="python" manual="import%20utime%0Aimport%20machine%0Aimport%20urequests%0Aimport%20ntptime%0Aimport%20network%0Afrom%20machine%20import%20I2C%2C%20Pin%2C%20RTC%0Afrom%20lcd_api%20import%20LcdApi%0Afrom%20i2c_lcd%20import%20I2cLcd%0A%0A%23%20IFTTT%20settings(%E9%9C%80%E8%87%AA%E8%A1%8C%E8%BC%B8%E5%85%A5IFTTT%E7%9B%B8%E9%97%9C%E8%B3%87%E8%A8%8A)%0AIFTTT_GOOGLE_EVENT%20%3D%20%22enter_your_google_event%22%0AIFTTT_LINE_EVENT%20%3D%20%22enter_your_line_event%22%0AIFTTT_KEY%3D%20%22enter_your_webhook_key%22%0AIFTTT_URL_GOOGLE_SHEET%20%3D'https%3A%2F%2Fmaker.ifttt.com%2Ftrigger%2F'%2BIFTTT_GOOGLE_EVENT%2B'%2Fwith%2Fkey%2F'%2BIFTTT_KEY%0AIFTTT_URL_LINE%20%3D'https%3A%2F%2Fmaker.ifttt.com%2Ftrigger%2F'%2BIFTTT_LINE_EVENT%2B'%2Fwith%2Fkey%2F'%2BIFTTT_KEY%0A%0A%23%20WiFi%20settings(%E9%9C%80%E8%87%AA%E8%A1%8C%E8%BC%B8%E5%85%A5WIFI%E5%B8%B3%E8%99%9F%E5%92%8C%E5%AF%86%E7%A2%BC)%0Awifi_ssid%20%3D%20%22enter_your_wifi_ssid%22%0Awifi_password%20%3D%20%22enter_your_wifi_password%22%0A%0A%23%20Initialize%20UART(%E5%88%9D%E5%A7%8B%E5%8C%96UART)%0Auart%20%3D%20machine.UART(1%2C%20baudrate%3D9600%2C%20tx%3Dmachine.Pin(8)%2C%20rx%3Dmachine.Pin(9)%2C%20timeout%3D1000)%0A%0Auart.init(9600%2C%20bits%3D8%2C%20parity%3DNone%2C%20stop%3D1)%0A%0A%23%20LCD%20initialization%20(LCD%20%E5%88%9D%E5%A7%8B%E5%8C%96)%0AI2C_ADDR%C2%A0%C2%A0%C2%A0%C2%A0%20%3D%200x3f%0AI2C_NUM_ROWS%20%3D%202%0AI2C_NUM_COLS%20%3D%2016%0Ai2c%20%3D%20I2C(0%2C%20sda%3Dmachine.Pin(0)%2C%20scl%3Dmachine.Pin(1)%2C%20freq%3D400000)%0Alcd%20%3D%20I2cLcd(i2c%2C%20I2C_ADDR%2C%20I2C_NUM_ROWS%2C%20I2C_NUM_COLS)%C2%A0%C2%A0%0A%0A%23%20Initialize%20RTC%20(RTC%20%E5%88%9D%E5%A7%8B%E5%8C%96)%0Artc%20%3D%20RTC()%0A%0A%23%20Connect%20to%20the%20WiFi%20(WIFI%E9%80%A3%E7%B7%9A)%0Adef%20connect_wifi(ssid%2C%20password)%3A%0A%C2%A0%C2%A0%C2%A0%20wlan%20%3D%20network.WLAN(network.STA_IF)%0A%C2%A0%C2%A0%C2%A0%20wlan.active(True)%0A%C2%A0%C2%A0%C2%A0%20if%20not%20wlan.isconnected()%3A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20wlan.connect(ssid%2C%20password)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20while%20not%20wlan.isconnected()%3A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20pass%0A%0A%23%20Update%20the%20time%20from%20NTP%20server%20(%E6%9B%B4%E6%96%B0%E6%99%82%E9%96%93)%0Adef%20update_time()%3A%0A%C2%A0%C2%A0%C2%A0%20ntptime.host%20%3D%20'pool.ntp.org'%0A%C2%A0%C2%A0%C2%A0%20ntptime.settime()%0A%C2%A0%C2%A0%C2%A0%20tm%20%3D%20utime.localtime(utime.mktime(utime.localtime())%20%2B%2028800)%0A%C2%A0%C2%A0%C2%A0%20rtc.datetime((tm%5B0%5D%2C%20tm%5B1%5D%2C%20tm%5B2%5D%2C%20tm%5B6%5D%20%2B%201%2C%20tm%5B3%5D%2C%20tm%5B4%5D%2C%20tm%5B5%5D%2C%200))%0A%0A%23%20Get%20current%20time(%E5%8F%96%E5%BE%97%E7%9B%AE%E5%89%8D%E6%99%82%E9%96%93)%0Adef%20get_time()%3A%0A%C2%A0%C2%A0%C2%A0%20time%20%3D%20rtc.datetime()%0A%C2%A0%C2%A0%C2%A0%20current_hour%20%3D%20time%5B4%5D%0A%C2%A0%C2%A0%C2%A0%20current_minute%20%3D%20time%5B5%5D%0A%C2%A0%C2%A0%C2%A0%20current_second%20%3D%20time%5B6%5D%0A%C2%A0%C2%A0%C2%A0%20current_time%20%3D%20%22%7B%3A02d%7D%3A%7B%3A02d%7D%3A%7B%3A02d%7D%22.format(current_hour%2C%20current_minute%2C%20current_second)%0A%C2%A0%C2%A0%C2%A0%20return%20current_time%2C%20current_hour%2C%20current_minute%0A%0A%23%20Send%20data%20to%20IFTTT%20(%E5%82%B3%E8%B3%87%E6%96%99%E5%88%B0IFTTT)%0Adef%20send_to_ifttt(url%2C%20soil_temp%2C%20soil_vwc%2C%20state)%3A%0A%C2%A0%C2%A0%C2%A0%20data%20%3D%20%7B'value1'%3A%20str(soil_temp)%2C%20'value2'%3A%20str(soil_vwc)%2C%20'value3'%3A%20state%7D%0A%C2%A0%C2%A0%C2%A0%20request_headers%20%3D%20%7B'Content-Type'%3A%20'application%2Fjson'%7D%0A%C2%A0%C2%A0%C2%A0%20request%20%3D%20urequests.post(url%2C%20json%3Ddata%2C%20headers%3Drequest_headers)%0A%C2%A0%C2%A0%C2%A0%20request.close()%0A%0A%23%20Sensor%20Access%20Function%20(RS485%E6%84%9F%E6%B8%AC%E5%99%A8%E5%9B%9E%E5%82%B3%E8%B3%87%E6%96%99)%0Adef%20Sensor_Access()%3A%0A%C2%A0%C2%A0%C2%A0%20Read_SOIL_TEMP_HUMI_Command%20%3D%20bytes(%5B0x01%2C%200x03%2C%200x00%2C%200x06%2C%200x00%2C%200x02%2C%200x24%2C%200x0A%5D)%0A%C2%A0%C2%A0%C2%A0%20SOIL_buf%20%3D%20bytearray(11)%0A%C2%A0%C2%A0%C2%A0%20Sensor_Delay_mS%20%3D%2050%0A%20%20%20%20%20%20%20uart.write(Read_SOIL_TEMP_HUMI_Command)%0A%C2%A0%C2%A0%C2%A0%20uart.readinto(SOIL_buf)%0A%C2%A0%C2%A0%C2%A0%20utime.sleep_ms(Sensor_Delay_mS)%0A%0A%C2%A0%C2%A0%C2%A0%20SOIL_VWC_Data%20%3D%20(SOIL_buf%5B5%5D%20%3C%3C%208)%20%2B%20SOIL_buf%5B6%5D%0A%C2%A0%C2%A0%C2%A0%20SOIL_VWC_Value%20%3D%20int(SOIL_VWC_Data)%20%2F%201000%0A%C2%A0%C2%A0%C2%A0%20SOIL_TEMP_Data%20%3D%20(SOIL_buf%5B3%5D%20%3C%3C%208)%20%2B%20SOIL_buf%5B4%5D%0A%C2%A0%C2%A0%C2%A0%20SOIL_TEMP_Value%20%3D%20int(SOIL_TEMP_Data)%20%2F%20100%0A%C2%A0%C2%A0%C2%A0%20return%20SOIL_TEMP_Value%2C%20SOIL_VWC_Value%0A%0A%23%20Print%20on%20LCD%20(%E9%A1%AF%E7%A4%BA%E6%95%B8%E5%80%BC%E5%9C%A8LCD)%0Adef%20lcd_print(current_time%2C%20soil_vwc)%3A%0A%C2%A0%C2%A0%C2%A0%20lcd.clear()%0A%C2%A0%C2%A0%C2%A0%20lcd.putstr(%22TIME%3A%20%7Btime%7D%C2%A0%C2%A0%C2%A0%20VWC%3A%20%7Bvwc%3A.1f%7D%22.format(time%3Dcurrent_time%2C%20vwc%3Dsoil_vwc))%0A%0Adef%20main()%3A%0A%C2%A0%C2%A0%C2%A0%20state%20%3D%20%22%20Normal%20%22%0A%C2%A0%C2%A0%C2%A0%20connect_wifi(wifi_ssid%2C%20wifi_password)%0A%C2%A0%C2%A0%C2%A0%20update_time()%20%23%20update%20the%20time%20from%20NTP%20server%20at%20the%20start%0A%C2%A0%C2%A0%C2%A0%20lcd.putstr(%22WIFI%20is%20connected!%22)%0A%0A%C2%A0%C2%A0%C2%A0%20%23%20setting%20the%20initial%20time%20to%20a%20value%20that%20triggers%20the%20first%20send%0A%C2%A0%C2%A0%C2%A0%20last_sent_hour%20%3D%20-1%0A%C2%A0%C2%A0%C2%A0%20last_sent_minute%20%3D%20-1%0A%20%C2%A0%C2%A0%20line_flag%20%3D%20False%0A%0A%C2%A0%C2%A0%C2%A0%20while%20True%3A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20current_time%2C%20current_hour%2C%20current_minute%20%3D%20get_time()%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%23%20read%20sensor%20every%2015%20minutes%C2%A0%20(%E6%AF%8F15%E5%88%86%E9%90%98%E4%B8%8A%E5%82%B3%E6%95%B8%E5%80%BC%E5%88%B0Google%20Sheets)%0A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20if%20current_minute%20%25%2015%20%3D%3D%200%20and%20current_minute%20!%3D%20last_sent_minute%3A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20soil_temp%2C%20soil_vwc%20%3D%20Sensor_Access()%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20send_to_ifttt(IFTTT_URL_GOOGLE_SHEET%2C%20soil_temp%2C%20soil_vwc%2C%20state)%0A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20last_sent_minute%20%3D%20current_minute%0A%0A%23%20send%20to%20LINE%20sheet%20once%20every%20day%20at%207%3A00pm%20(%E6%AF%8F%E6%99%9A%E4%B8%83%E9%BB%9E%E4%B8%8A%E5%82%B3%E6%95%B8%E5%80%BC%E5%88%B0LINE)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20if%20current_hour%20%3D%3D%2019%20and%20current_minute%20%3D%3D%200%20and%20line_flag%20%3D%3D%20False%3A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20soil_temp%2C%20soil_vwc%20%3D%20Sensor_Access()%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%23send_to_ifttt(IFTTT_URL_GOOGLE_SHEET%2C%20soil_temp%2C%20soil_vwc%2C%20state)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20send_to_ifttt(IFTTT_URL_LINE%2C%20soil_temp%2C%20soil_vwc%2C%20state)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20line_flag%20%3D%20True%0A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%23%20reset%20line_flag%20after%207%3A00pm%20(%E9%87%8D%E7%BD%AEline_flag)%0A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20if%20current_hour%20%3D%3D%2019%20and%20current_minute%20%3E%200%3A%0A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20line_flag%20%3D%20False%0A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%23%20send%20to%20LINE%20when%20soil_vwc%20is%20between%200%20and%2010%20(%E7%95%B6%E6%B7%B9%E6%B0%B4%E6%99%82%E6%9C%83%E7%99%BC%E7%B7%8A%E5%A0%B1)%0A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20soil_temp%2C%20soil_vwc%20%3D%20Sensor_Access()%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20if%200%20%3C%20soil_vwc%20%3C%3D%2010%3A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20state%20%3D%20%22%20ALERT!!%20%22%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20send_to_ifttt(IFTTT_URL_LINE%2C%20soil_temp%2C%20soil_vwc%2C%20state)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20send_to_ifttt(IFTTT_URL_GOOGLE_SHEET%2C%20soil_temp%2C%20soil_vwc%2C%20state)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20else%3A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20state%20%3D%20%22%20Normal%20%22%0A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%23%20print%20on%20LCD%20every%20second%20(LCD%E6%AF%8F%E7%A7%92%E6%9B%B4%E6%96%B0%E4%B8%80%E6%AC%A1%E9%A1%AF%E7%A4%BA%E7%95%AB%E9%9D%A2)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20lcd_print(current_time%2C%20soil_vwc)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20print(current_time%2C%20soil_vwc)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20utime.sleep(1)%C2%A0%20%23%20sleep%20for%201%20second%0A%0A%23%20Run%20the%20main%20function%20(%E5%9F%B7%E8%A1%8C%E4%B8%BB%E7%A8%8B%E5%BC%8F)%0Amain()" message="Alert_IFTTT_LINE_GOOGLE_settime_blog.py" highlight="" provider="manual"/]
- 安裝位置
筆者將裝置設置在地下室容易淹水的地方,由於感測器很靈敏,所以使用海綿來吸水,到一定程度後感測器就會發出通報 (下圖左)。裝置運作時,可由外接 LCD 看到當下的時間和濕度。
[gallery columns="2" ids="59287,59288"]
6. 實際執行
執行影片如本文開頭,為了較快看到效果,筆者設計是每秒上傳一次資料到雲端,請根據實際狀況來修改這個更新頻率。
留言 💬 (0)
還沒有留言,來當第一個。