智能盆栽澆水寶






專案起源

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



功能說明


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

— 自動澆水 —

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

— 即時檢視 —

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

— 遠端監控 —

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

— 提醒通知 —

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

— 記錄圖表 —

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



準備材料


86Duino Zero
MicroSD 卡
USB Wifi
USB Display / TFT LCD
USB Camera
USB HUB
超音波模組
沉水馬達與開關控制電路
土壤濕度分壓電路



硬體架設


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

然後將線焊上,再焊上一顆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影片 —





相關連結


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.