智能盆栽澆水寶





專案起源

此專案源起自妖怪舞專案時魔人整理辦公室外空間時,
老大見狀說:「這塊空間做成公園種種花草似乎不錯。」
魔人無心的附和了一句:「那我們可以做個自動澆水的系統耶!」
老大思考了一下說:「這真是個好主意!」
隨後魔人就被指派為此專案的負責人。
智能盆栽澆水寶(以下簡稱栽寶 ZaiBo),智能盆栽澆水寶 ZaiBo 是一個在 86Duino Zero 上運行 Linux 實作的自動澆水裝置,使用 USB WiFi 網卡做一個 IoT 系統。


功能說明


ZaiBo 分為兩種模式:
第一種為完整版,使用 USB Display 提供觸控功能、自動澆水並且有遠端監控等功能。
第二種為精簡版,精簡版雖然沒有自動澆水功能,但它可以提醒使用者澆水,並且採用 TFT LCD 做為簡易的螢幕,而網站功能皆相同。
ZaiBo 除了把原始碼公開以外,也將建構教學也一併公開,任何人都可以自由使用、修改、散佈。

— 自動澆水 —

使用者可以依據不同品種的盆栽來設定土壤濕度低於多少才澆水。

— 即時檢視 —

使用者可以在 ZaiBo 上的觸控螢幕進行互動。

— 遠端監控 —

使用者可以開啟 ZaiBo 網站進行即時監控,支援即時影像與資料顯示,也可以使用網站功能進行遠端控制。

— 提醒通知 —

使用者可以設定土壤濕度過低時寄信提醒使用者澆水,也可以開啟自動澆水模式,並設定水桶水量不足時可以寄信提醒使用者補水。

— 記錄圖表 —

ZaiBo 也有記錄功能,使用者可以在網站上看到過往的圖表資料。


準備材料

  1. 86Duino Zero
  2. MicroSD 卡
  3. USB Wifi
  4. USB Display / TFT LCD
  5. USB Camera
  6. USB HUB
  7. 超音波模組
  8. 沉水馬達與開關控制電路
  9. 土壤濕度分壓電路



硬體架設


首先我們需要兩根可以導電的鐵棒(我使用露營用的鐵棒):

然後將線焊上,再焊上一顆 200Ω 的可變電阻(方便依據土壤品質調整分壓阻值),再分別接到 3.3V、A4、Gnd 腳位上:
如此一來就可以使用兩根鐵棒簡單的量測土壤目前的濕度。
因為一般直流抽水馬達會有很多的雜訊,如果要做過濾雜訊的電路會麻煩許多,所以澆水功能的沉水馬達建議使用電腦水冷系統用的馬達。
而開關電路甚至可以很簡單的使用電晶體解決。(當然不是好辦法,各位也可以使用繼電器來作開關)
而超音波模組是用來量測水桶的水量的,我們可以利用水面高度與桶子深度來簡易的計算剩餘的水量。
而量測溫度濕度及大氣壓力,則是使用 RM-G185 模組。


環境設定


首先,可以依照官方教學在 SD 卡上安裝 L86duntu 作業系統:

安裝完後就可以把安裝有 L86duntu 的 SD 卡插入 Zero 的 SD 卡插槽後通電開機,由於是使用 Zero,所以我們必須要遠端網路連線的方式來登入 L86duntu,詳情一樣可以參照官方教學

登入後首先解決開機的問題,L86duntu 在不正常關機後重開機會在下面看到的選單上等待:
如果不是使用 One 接上顯卡,我們很難知道 L86duntu 是不是卡在這個選單上了,所以我們先將這個功能設定為自動關閉。
首先將 /etc/grub.d/00_header 檔案裡的

make_timeout() {... set timeout = -1 ...}

修改為

make_timeout() {... set timeout = 10 ...}

﹝我們可以直接使用 vim 的搜尋功能 /make_timeout 直接找到該列﹞
再將 /etc/default/grub 檔案中新增一列

GRUB_RECORDFAIL_TIMEOUT=$GRUB_TIMEOUT

最後輸入指令
$ update-grub
修改完後就不會出現選單的問題囉!
接下來我們要安裝 SMTP Server,因為 ZaiBo 的提醒功能是利用寄信來提醒通知的,所以我們需要有一個可以寄送郵件的伺服器。
先接上網路線後執行下面這一行指令來安裝相關套件:

$ sudo apt-get install mailutils

在安裝途中會出現設定視窗,按 Tab 切換到 OK 後進行下一步設定:
接下來將選項選擇到「Internet Site」,然後按 Tab 鍵到 OK 後按 Enter 鍵,接著就會完成 Postfix 的設定了:
接下來可以依照你的喜好設定信箱名稱,然後一樣按 Tab 選到 OK 按 Enter 鍵,之後會看到完成畫面。
接下來我們要安裝 SDL 的套件,因為在 USB Display 上就是使用 SDL 來繪製圖形介面的(如果你要做的是精簡版的 ZaiBo,可以不安裝 SDL),我們先來看看如何安裝 SDL:
我們需要用到的其他函式庫有 SDL_ttf、SDL_image、SDL_gfx,所以我們到 SDL 官網上下載原始碼,用 FileZilla 將檔案傳到 L86duntu 上。
解壓縮後,之後到各個目錄輸入指令開始安裝:

$ tar zxvf filename.tar.gz
$ cd filename
$ ./configure && make && make install

在此以 SDL-1.2.15 為例:

$ tar zxvf SDL-1.2.15.tar.gz
$ cd SDL-1.2.15
$ ./configure && make && make install

全數安裝完後我們就可以開啟我們的程式來做測試了。

— 擴充 1G 的 swap —

由於我們安裝了 L86duntu 又使用了很多的周邊裝置,所以 128M 的記憶體或許稍顯不足,所以我們可以將 swap 擴充,讓硬碟的一些空間拿來當作虛擬記憶體,指令如下:

$ cd /var
$ fallocate -l 1G swapfile
$ chmod 600 swapfile
$ mkswap /var/swapfile
$ swapon /var/swapfile

然後我們要在每一次開機時讓它自動啟動,所以我們需要增加 /etc/fstab 的內容:

$ /var/swapfile    none    swap    sw    0    0

修改完後我們可以重開機,輸入指令 free –m 來確認是否有變成 2G 的 swap。

— 使用 USB WiFi —

在 86Duino 上使用 USB WiFi 很簡單,如果各位也是使用同一個 USB WiFi 晶片的話就可以照著官網的教學建立 WiFi。
我在此有將指令稍做修改,因為我們的 ZaiBo 必須要自動連線,所以要自己辨識自己的網路編號:

$ cd /home/dmp
$ modprobe rt2800usb
$ echo 148f 5370 | tee /sys/bus/usb/drivers/rt2800usb/new_id
$ sleep 1
$ ID=$(exec iwconfig | grep -o -P "wlan[0-9]*")
$ echo $ID > /tmp/usbwifiID
$ ifconfig $ID up
$ killall wpa_supplicant
$ killall wpa_supplicant
$ killall wpa_supplicant
$ killall wpa_supplicant
$ killall wpa_supplicant
$ killall wpa_supplicant
$ killall wpa_supplicant
$ wpa_supplicant -i $ID -D nl80211 -c /etc/wpa_supplicant.conf -B
$ sleep 1
$ udhcpc -i $ID

在這段指令中,會將網卡的名稱存到 /tmp/usbwifiID 中,而在 UI 顯示的程式中也有來存取這個名稱,所以此一修改是必要的。

— 使用 USB Display —

和 USB WiFi 一樣,USB Display 在 86Duino 的官網一樣有詳盡的教學,但我們不需要進入圖形介面,所以可以自行修改 run_usbdisp.sh 內的內容:

$ modprobe rp_usbdisplay
$ sleep 1
$ modprobe -r rp_usbdisplay
$ modprobe rp_usbdisplay
$ sleep 1
$ modprobe -r rp_usbdisplay
$ modprobe rp_usbdisplay
$ cp /home/dmp/rpusbdisp-master/drivers/linux-driver/xserver_conf/10-disp.conf /usr/share/X11/xorg.conf.d/
— 開機時自動啟動所有的裝置 —

首先我們在 /etc/init.d/ 下建立一個檔案,在此我以 plant 為例。
建立完後在裡面輸入內容:﹝可能因裝置不同需要做更動﹞
儲存完成後,我們要先將此檔案的權限修改為可執行:

$ chmod 755 /etc/init.d/plant

然後使用 update-rc.d 更新開機 script

$ update-rc.d plant start 99 1 2 3 4 5 6 . stop 80 0 .

設定完後每次重新開機就會啟動這支 script,而我在這支 script 中也有做判斷是否使用 USB display 的裝置,若是沒有接上 USB display 的話就會啟用 TFT LCD 來做顯示。


程式解說

— UI_display.cpp —

在此函式中我利用 SDL 去讀取背景圖片以及文字字型。

bool load_files()
{
	if(mode == 0)
		background = SDL_LoadBMP("background2.bmp");
	else
		background = SDL_LoadBMP("background.bmp");
    loading = SDL_LoadBMP("loading.bmp");
    buttonSheet = SDL_LoadBMP( "water.bmp" );
    font = TTF_OpenFont( "mvboli.ttf", 12 );
    //...
    return true;
}
— app.js —

在這段程式中,我設定了一個每隔 500ms 刷新一次的 Interval,用來觀測是否有澆水事件發生,若是發生則起動幫浦澆水。

setInterval(function IsWatering(){
	if(Watering){
		pump_time = Date.now();
        pump_speed += .1;
		if(pump_speed >= 1)
            pump.write(1);
        else
			pump.write(pump_speed);
    }else if(pump_time + 5000 > Date.now()){
        pump_speed += .1;
		if(pump_speed >= 1)
            pump.write(1);
        else
			pump.write(pump_speed);
	}else{
		pump_speed = 0;
		Watering = false;
		pump.write(0);
	}
},500);



成果展示

— 網站功能 —

在 ZaiBo 開機後會自動開啟網站功能,各位可以看到簡單易懂的介面:
Current State 也就是當前所有的狀態,分別是水箱水量、土壤濕度、空氣濕度、溫度以及大氣壓力。
而下方可以看到歷史記錄的圖表,讓使用者快速掌握近期的狀況。
Live Stream 也就是即時串流,使用者可以在直接連上網站,就可以透過 Camera 知道目前的狀態。
在上方的橫欄也有 Settings 可以做設定:
Settings 中提到的兩種模式,Warning mode 也就是精簡版,只會在該澆水時寄信提醒你,而 Watering mode 則是完整功能版,也就是將抽水馬達澆水的功能也加進去了,會在水箱沒水時提醒補水。
由於是網頁,所以使用智慧型手機連線也是可以的!

— 寄信功能 —

ZaiBo 是利用寄信來通知使用者該補水或澆水,以下可以看到 ZaiBo 寄信通知的功能:

— DEMO影片 —




相關連結


[1] 本專案 Github


自造遊樂園主頁面

The text of the 86Duino reference is licensed under a Creative Commons Attribution-ShareAlike 3.0 License. Code samples in the reference are released into the public domain.