智能盆栽浇水宝





专案起源

此专案源起自妖怪舞专案时魔人整理办公室外空间时,老大见状说:「这块空间做成公园种种花草似乎不错。」
魔人无心的附和了一句:「那我们可以做个自动浇水的系统耶!」
老大思考了一下说:「这真是个好主意!」
随后魔人就被指派为此专案的负责人。
智能盆栽浇水宝(以下简称栽宝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.