用树莓派DIY一个智能家居服务器

来自树莓派实验室老司机群 Pokebox 的投稿~
高考结束啦~来用树莓派DIY一下自己的智能家居吧~
其实这东西我自己已经用了一年了~现在就来写个教程~嘿嘿……
先上个图
20160626192247896-0
有点乱23333
这是我的房间书柜,也是我的工作台……书柜的侧边是树莓派搭建的物联网服务器~
来一只近图~
20160626192247673-0
这就是服务器的近照啦~
我用的是树莓派A+作为服务器的主控,所有的工作都由它完成。
树莓派A+是单核的处理器,RAM仅256MB,不过如果不是作为复杂工作的话……也足够了~
这里,它的主要工作就是收集房间和室外的环境数据并上传至yeellink,同时获取yeellink上的开关数据控制房间里的灯,门,音响等设备的开关。
以及,在晚上下晚修我回到家的时候,自动打开灯~睡着了后自动关灯~

先来简单介绍一下,这里需要用到一些什么东西。如上面那张图,树莓派是肯定要有的~当然,什么版本都可以……因为实际上这里也没用多少GPIO,以前的A,B版本都可以……
然后,树莓派左下角那个蓝色的是声卡和音响的集成驱动,用来推动喇叭的~使用5V的电源,当然大家可以直接找个小音箱来代替~~
然后下面那一堆线是面包板,用来分配电源和继电器控制,以及……比较方便接线吧23333.各种传感器可以直接插面包板上,这样就省去了焊线的麻烦。
另外,由于我用的是树莓派A+,没有网络接口,所以用了一个8口的带电源HUB连接无线网卡和其他的比如USB串口等设备。HUB贴在树莓派上面点,没拍到。
再下面是电源盒,这里我用的是台式机电脑的电源~为什么用台式机电源呢?这有很大的好处。
台式机电源有12V,5V和3.3V,并带有一路5V VSB电源,以及还可以用GPIO控制电源整体开关。这就非常适合用来做服务器了,因为我的LED灯条是12V的,电磁锁也是12V的,而树莓派和USB设备都需要5V,一些传感器则需要3.3V,正好一个电源全部搞定它。同时在一些需要耗电的东西不需要用的时候,比如LED灯条,那我还可以把整个电源系统关掉省电~而在关掉总电源的时候,5V VSB是一直保持输出的,就可以用这一路电源给树莓派持续供电~ 是不是觉得很方便?

简单介绍完整个系统了,来看看接线
20160626192247323-0
这是整个系统的接线图~面包板左边那一坨就是台式机电源的ATX接口。
最下面的电机是电磁锁。
音响接的是驱动板。
以及这里用了个arduino mini,这是后来加上的,用来进行AD转换一些传感器数据然后通过串口发给树莓派。
下面那些继电器我用洞洞板制作成了一个模块,方便接线用。
20160626192247488-0

20160626192247208-0
正面和背面。和我最终做出来的成品稍微有点点出入,因为我在制作时根据实际优化了一下布局。但是大致电路是没什么变化的,大家可以参考制作。
这个继电器模块主要是用来控制12V设备的, 比如打开LED灯条,开锁等,都是用树莓派GPIO驱动三极管让继电器吸合导通12V的电源让设备工作。
这里我要特别强调!继电器和电磁锁都为磁感设备,在吸合和释放时因为磁生电效应会产生很强的反向电动势,这个电动势如果不采取措施很容易造成三极管甚至树莓派软击穿!导致树莓派停止工作甚至损坏!所以在每个继电器和电磁锁的线圈两端我都接有一个反向安装的二极管,用来吸收线圈在释放时产生的反向电动势,以保护设备。

好了~硬件大概就介绍到这。剩下的是软件……
先是介绍一下,通过yeellink控制LED灯和门锁等设备的控制方案,这个程序还包含了指定时间内检测我是否在家,比如在晚上,如果我回来了则自动开灯。这个是通过ping我手机的IP地址是否有回应来完成判断的。毕竟……出门肯定带手机吧……所以,当ping手机不通的时候,说明我不在家了,就关掉房间里的设备省电。当我回到家时,手机自动连接wifi后,ping通,说明我回来了,然后自动打开灯~

这一切都是通过bash脚本写的~

#!/bin/bash
##2015年9月29日 23:32:22
echo "##VI	2016年4月8日 22:56:12	## V2.2"
TDIR=/tmp
mkdir -p $TDIR
export PATH=$PATH:/usr/local/bin
gpio -g write 21 1
gpio -g mode 21 out	##电源开关	拉低开
gpio -g write 26 1
gpio -g mode 26 out	##桌面灯条	拉低开
gpio -g write 19 1
gpio -g mode 19 out	##桌面灯条	拉低开
gpio -g write 13 1
gpio -g mode 13 out	##柜子锁	拉低开
gpio -g write 6 1
gpio -g mode 6 out	##门锁		拉低开

FI35=0
CLE_TIME=0	##检测计数器
##你API的设备号
DEV=
##你传感器的编号
SW_POWER=
SW_DSKLED=
SW_DOOR=
SW_FORCER=
SW_CHANGE=

getdev(){
	DEVS=$1
	wget http://api.yeelink.net/v1.0/device/${DEV}/sensor/${DEVS}/datapoints -O $TDIR/sa${DEVS} -T 5 &> /dev/null
	FTIME=`cat $TDIR/sa${DEVS} | sed 's/.*\"\:\"//g;s/\"\,\".*$//g'`
	FYMD=`echo $FTIME | sed 's/T.*$//g'`
	FHMS=`echo $FTIME | sed 's/^.*T//g'`
	VAL=`cat $TDIR/sa${DEVS} | sed 's/^.*value\"\://g;s/\}//g'`
	if [ ! -e $TDIR/savetime${DEVS} ];then
		echo "" > $TDIR/savetime${DEVS}
		if [ "$DEVS" == "$SW_POWER" ];then
			if [ "$VAL" == "1" ];then
				gpio -g write 21 0
			else
				gpio -g write 21 1
			fi
		fi
		if [ "$DEVS" == "$SW_DSKLED" ];then
			if [ "$VAL" == "1" ];then
				gpio -g write 19 0
			else
				gpio -g write 19 1
			fi
		fi
	fi

	
	echo -e "\e[31;1m$FTIME \e[34;1m# $FYMD ## $FHMS\e[32;1m $DEVS \e[33;1m $VAL\e[0m"
	if [ "$FYMD" == "`date +%Y-%m-%d`" ];then
		echo ##操作日期为当天才进行下面的操作
		if [ "$FHMS" != "`cat $TDIR/savetime${DEVS}`" ];then
			echo ##操作时间不和上次的记录相同才进行下面的操作
			if [ "`echo $FHMS | awk -F ':' '{printf $1}'`" == "`date +%H`" ];then
				A=`echo $FHMS | awk -F ':' '{printf $1}'`
				echo -e "\e[31;1m$A\e[0m"
				##if [ "$VAL" == "1" ];then
					if [ "$DEVS" == "$SW_DOOR" ];then	#门锁
						gpio -g write 6 0
						sleep 2
						gpio -g write 6 1
					elif [ "$DEVS" == "$SW_FORCER" ];then	#柜子锁
						gpio -g write 13 0
						sleep 2
						gpio -g write 13 1
					elif [ "$DEVS" == "$SW_POWER" ];then	#电源开关
						if [ "$VAL" == "1" ];then
							gpio -g write 21 0
						else
							gpio -g write 21 1
						fi
					elif [ "$DEVS" == "$SW_DSKLED" ];then	#桌面灯条
						if [ "$VAL" == "1" ];then
							gpio -g write 19 0
						else
							gpio -g write 19 1
						fi
					elif [ "$DEVS" == "$SW_CHANGE" ];then	#充电座
						if [ "$VAL" == "1" ];then
							gpio -g write 26 0
						else
							gpio -g write 26 1
						fi
					fi
					echo "$FHMS" > $TDIR/savetime${DEVS}
				##fi
			fi
		fi
	fi
}

##给LED点阵模块发送时间数据
ledtime(){
	if [ -e /dev/ttyUSB0 ];then
		echo "\`wr`date +%H%M`" | microcom -p /dev/ttyUSB0 -s 115200
	fi
}

##先初始化锁和充电开关
getdev $SW_DOOR
getdev $SW_FORCER
getdev $SW_CHANGE
getdev $SW_DSKLED

while :
do
	getdev $SW_POWER
	getdev $SW_DSKLED
	getdev $SW_DOOR
	getdev $SW_FORCER
	getdev $SW_CHANGE
	
	if [ "`date +%H%M`" -ge "1900" ];then	##时间在下午5点20后
		if [ "$FI35" == "0" ];then	##是否查找过设备233)0否不在线 1是在线
			if [ "`ping 192.168.1.233 -c 1 -S 1 &> /dev/null;echo $?`" == "0" ];then	##查找手机是否在线
				gpio -g write 21 0
				gpio -g write 19 0
				FI35=1
			fi
		elif [ "`date +%H%M`" -ge "1905" ];then	##如果手机不在线则判断时间是否在晚上7点以后
			if [ "$CLE_TIME" -le "5" ];then
				((CLE_TIME++))
				echo "CLE_TIME $CLE_TIME"
			else
				CLE_TIME=0
				if [ "`ping 192.168.1.233 -c 1 -S 1 &> /dev/null;echo $?`" == "1" ];then	##如果不在线则清除标记
					if [ "$CLOSE_LED" == "0" ];then
						CLOSE_LED=1
					else
						CLOSE_LED=0
						gpio -g write 21 1	##关灯关电源
						gpio -g write 19 1
						FI35=0
					fi
				fi
			fi
		fi
	elif [ "`date +%H%M`" -le "0230" ];then	##时间是否在凌晨2点半以内
		if [ "$FI35" == "0" ];then	##如果是,则判断手机是否在线
			if [ "`ping 192.168.1.233 -c 1 -S 1 &> /dev/null;echo $?`" == "0" ];then	##如果手机在线则开灯
				gpio -g write 21 0
				gpio -g write 19 0
				FI35=1
			fi
		fi
	elif [ "$FI35" != "0" ];then	##否则关灯
		FI35=0
		gpio -g write 19 1
		gpio -g write 21 1
	fi
		
	sleep 1
	ledtime
	gpio -g write 6 1
done

然后,是数据上传的程序。通过检测环境数据然后上传到yeellink上,然后yeellink可以自动记录并绘制图表,可以很直观的看到最近的气象温度变化以及树莓派的状态。
20160626192247985-0
额……好像光敏传感器有点问题……不管啦…然后可能由于室外18B20被太阳直接照射的原因……最近温度一直很高……
然后晚上的温度还是比较正常的……(广西真的好热!)
20160626192247377-0

#!/bin/bash
##连接物联网发送CPU温度
##BY PokeBox
##创建于:2014年9月27日
##最后修改:2014年9月30日 02:04:38
echo "	##Start YeeLink_Temp......"
APIKEY=''	##APIKEY
TMPDIR=/tmp/my		##临时数据目录
TTYFIFO=/run/ttyAMA0.fifo	##/tmp/ttyAMA0.fifo
sudo modprobe w1-gpio
sudo modprobe w1-therm
gettime(){
	YY=`date +%Y`;MO=`date +%m`;DD=`date +%d`
	HH=`date +%H`;MM=`date +%M`;SS=`date +%S`
}
getCPUMHZ(){
	deviceid=你的设备号
	sensorid=你的传感器号
	VAL=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq | awk '{print $1/1000}'`
	echo -e "\e[36;1mCPU_MHz : ${VAL}\e[0m"
}

getCPUdata(){		##获取CPU数据
	deviceid=你的设备号					##设备号
	sensorid=					##传感器号
	VAL=`cat /sys/class/thermal/thermal_zone0/temp | awk '{print $1/1000}'`
}
getCPULoad(){		##获取CPU使用率
	deviceid=你的设备号
	sensorid=
	VAL=$(top -b -n 2 | grep ^%Cpu | sed -n "2p" | sed -e 's/^.*://g;s/..,//g;s/st//g' | awk '{print "scale=1; 100-" $4 }' | bc)
	echo -e "\e[36;1mCPU_USER : ${VAL}\e[0m"
}

## 删除数据点 http://api.yeelink.net/v1.0/device/你的设备号/sensor/传感器号/datapoint/时间点
getbdata(){		##获取18b20温度数据室内
	deviceid=你的设备号					##设备号
	sensorid=					##传感器号
	VAL=`cat /sys/bus/w1/devices/28-000005823549/w1_slave | grep 't=' | sed 's/^.*t=//g' | awk '{print $1/1000}'`
	echo -e "\e[36;1m18B20_IN : ${VAL}\e[0m"
}
getboutdata(){		##获取18b20温度数据室外
	deviceid=你的设备号					##设备号
	sensorid=					##传感器号
	VAL=`cat /sys/bus/w1/devices/28-00000581ea9e/w1_slave | grep 't=' | sed 's/^.*t=//g' | awk '{print $1/1000}'`
	echo -e "\e[36;1m18B20_Out : ${VAL}\e[0m"
}
GetPowerTempData(){
	sensorid=
	VAL=`cat /sys/bus/w1/devices/28-031604d2d0ff/w1_slave | grep 't=' | sed 's/^.*t=//g' | awk '{print $1/1000}'`
        echo -e "\e[36;1m18B20_Power : ${VAL}\e[0m"
}
getlight(){
	sensorid=
	VALa=`tac ${TTYFIFO} | grep -a 'AD0' | sed -n '2p' | awk '{print $3}' | sed 's/\r//'`
	VAL=`echo "1024 - ${VALa}" | bc`
	echo -e  "\e[36;1mLux :	${VAL}\e[0m"
}

senddata(){		##发送数据
	gettime
	echo "{
  \"timestamp\":\"${YY}-${MO}-${DD}T${HH}:${MM}:${SS}\",
  \"value\":${VAL}
}" > $TMPDIR/datafile.txt
	URL="http://api.yeelink.net/v1.0/device/${deviceid}/sensor/${sensorid}/datapoints"	##物联网地址
	curl --request POST --header "U-ApiKey: ${APIKEY}" --data-binary @$TMPDIR/datafile.txt ${URL}
}
oraynewph status &
while :
do
	getCPUMHZ;senddata	##CPU频率
	getCPUdata;senddata	##CPU温度
	getCPULoad;senddata	##CPU使用率
	getlight; senddata	##室外亮度
	getbdata
	TMPVAL=$(echo ${VAL%.*})
	if [ "$TMPVAL" -le "0" ];then
		echo 1 &> /dev/null
	else
		senddata	##室内温度
	fi
	getboutdata
	TMPVAL=$(echo ${VAL%.*})
	if [ "$TMPVAL" -le "0" ];then
		echo 1 &> /dev/null
	else
		senddata	##室外温度
	fi
	GetPowerTempData
	TMPVAL=$(echo ${VAL%.*})
        if [ "$TMPVAL" -le "0" ];then
                echo 1 &> /dev/null
        else
                senddata        ##电源温度
        fi

	sleep 2m	##间隔2分钟发送一次
done

上面是发送传感器数据到yeellink的bash代码,大家如果需要的话……自己去yeellink注册然后创建设备和传感器,然后把你的APIKEY和设备传感器号填到那些对应的变量上就可以用了……然后,上面那三个18B20的设备号是我的18B20的设备号,每一个18B20都有唯一的设备号,大家自己去修改。

除此之外,大家还可以通过树莓派上的crontab来创建任务,比如在指定时间打开音响播放音乐来做闹钟~
20160626192247312-0
20160626192247665-0
这是我用饮料罐自己DIY的音响,配合那个驱动板使用,这样的低音炮,妈妈再也不用担心我起不来床了~

然后,仔细看的话,大家也许发现第一段代码里有一条发送时间给LED点阵的函数,是的,那个函数是用来驱动这货的……
20160626192247526-0
因为我房间里没有钟,甚至……我家里都没有钟!所以就自己DIY吧……下面是其他时间段的效果
20160626192247301-0
20160626205550888-0
有没有觉得很6?!赶紧拿起你手中的树莓派DIY一个吧!更多创意,等你来创造!大家记得把自己的作品跟帖哦!


45 评论

  1. 设置定时,在2点半后关掉。按自己平时睡眠习惯来设置定时,入睡后自动关掉就可以。

  2. 回复CCS:设置定时,根据自己睡眠习惯在睡着后关掉就可以。比如我上学时1点多睡,到睡着差不多30分钟这样。然后我就设置2点30自动关灯。

  3. 设置定时,根据自己睡眠习惯在睡着后关掉就可以。比如我上学时1点多睡,到睡着差不多30分钟这样。然后我就设置2点30自动关灯。

  4. 弄这些并不需要太多时间啊,高中生活又不是一定是一大堆作业写到深更半夜。我们学校还有社团活动,平时在学校也可以在社团弄这些东西。而且这个项目有很多东西在我初中就已经弄出来了,现在不过是把那些东西重组起来而已。

  5. 这个书桌乱的我报警了233333
    作为程序员外加整洁控给楼主高中生技术能力给书桌0分哈哈哈

  6. 看到yeelink 之类的我就知道又做了一个垃圾业余产品,真不明白现在人的脑子是怎么想的,别人说这个东西应该这么这么做,你也就按照这种方法做了,请问你这么做有什么意义,做得再好也是一个没有一点自己想法的垃圾,难道不用云、APP就做不出东西了,考虑过安全问题吗,考虑过便捷问题吗,蠢的人永远是将简单的东西复杂化,请问假如别人向你推出 这样的产品你会去用吗,换作我我肯定会立马用锤子砸了

  7. 首先为楼主点个赞。再致YEJS:楼主不是产品开发工程师,你的要求有点高了。本来这就是一个实验,也算是个创意,用PI实现一些实用的功能。这些活动,更多是是一种思路和实现功能的动手能力。相信在动手的过程中楼主也会得到更多的收获。一个高中生,利用业余时间搞出这些东西也难能可贵了。难道你更喜欢只会考试的呆子!利用现有云,APP,手中器件来实现一些功能有什么不好。我们更需要是一种“创客”精神!只要楼主一如既往的坚持下去,相信你所说的一切都不是问题。

  8. YEJS有什么资格这样说一个高中生,楼主用业余时间做成这样很不错了。另外有本事秀出你做的东西啊,键盘侠

  9. 同楼上,YEJS喷子无疑,敢情就他自己是大牛,别人都是业余的。要评价一件作品也要看定位,如果你感觉自己的作品很牛也可以拿出来分享一下,让大家看到你有多牛,而不是在这无脑喷。

  10. 脚本看着头晕 到处都是if 难道不知道用switch流控么 up主化简为繁的本领真是强 不过也亏up主有这么大的耐心 一点点调试 希望能回归本源 把这些一堆繁琐的东西归纳集成 所谓合久必分分久必合 那时定会是另一个高度

  11. 谢谢YEJS的批评,是的,您说的没错,这套智能家居使用了yeellink的物联网服务器,并且也全公开,使用的底层代码也仅仅是bash脚本,确实是很垃圾,如果我用这些东西来作为产品我自己也会先一锤子砸掉。但是可能您对这篇文章的理解存在一些误区,这篇文章仅仅是想分享自己的一些DIY创意和心得,因为使用的是树莓派,而不是一个成品的产品,如果我使用的是商业化产品,估计也就不会有这篇文章了。因为商业的东西并不存在太多DIY的价值,同时也涉及一些商业的机密等。

    这篇文章,表达的仅仅是树莓派可以用来做这些事情,可以通过web,通过脚本来处理这些硬件上的事情。因为在众多树莓派玩家之中,有入门玩家,有初级玩家,更有高端玩家,我们在论坛,在博客发布自己的一些制作心得仅仅是为了和大家一起学习和交流;和入门玩家交流,我们可以从中认识更多新朋友;和高端玩家交流,可以得知自己的缺陷。因为我们(至少我)还是个学生啊~
    就像LEEZQANG所说的那样,我在代码里使用了大量的if语句,确实有点繁杂,那一部分elif的语句确实是可以写成
    case $DEVS in
    的方式来简化代码,毕竟代码的写法有很多种,这只是其中一种。我也不能说这就是一串好代码,好的东西都是对比出来的嘛~

    不管怎么说,都感谢大家的各种批评和意见,这才是共享的意义啊~

  12. 加油 哈哈 很厉害 我也想弄个玩 不过我大概不会用bash脚本 可读性差 准备用nodejs

  13. 最近在考虑用树莓派搭搭hadoop集群,比较感兴趣。没赶上楼主这样的好机会,上学期间都没接触过。话说第一眼看到楼主发的图片很难受。忒乱了。

  14. 天那 > < born to be a geek~~~ 这样的专业知识、动手能力、胸怀谈吐真的很难联系到现在只会死读书死做题的高中生。反观自己都大学了还整体稀里糊涂的,真是惭愧。不知道楼主毕业了没,最后念了什么专业,有没有什么新的实验和动态啊。

    btw,YEJS这种典型的键盘侠,loser的戾气隔着屏幕都熏到我的眼睛了。不知他有多专业,有多少了不起的商业作品。论坛里大部分都是爱好者,来学习和讨论的。怎么着,就他一个人有专业眼光,来谈投资项目的?连个自己的site都不留,diss别人的同时也让好我们瞻仰一下他的专业高度啊。新手看到这篇文章都是佩服和羡慕,真正的业内大佬也只会觉得后生可畏,孺子可教。这人居然说楼主“垃圾业余蠢不知道脑子怎么想的”,还要“拿锤子砸掉”别人的作品,如此心胸狭隘言语粗鲁。后面翻到楼主的回复,谦虚礼貌有理有据,这鲜明对比……哎哟我这小暴脾气…… Anyway, shame on him!!

  15. 小伙子加油,不错,有 maker 的潜质, 继续努力哈!
    另外, 除了 shell, 还可以尝试一下 python, 面向对象编程的话,可能更加清晰明了.
    而且….你的桌面真的无处下手..哈哈
    有 geek 的潜质啊!加油…
    对于留言里面的不和谐的声音, 可以无视了. 远离即可.

  16. 我感觉他挺厉害的了。很多的新产品都是模仿前辈,在前辈的基础上增加自己思想,创新真的很难!!!!

  17. 那个喷子是个loser吧,楼主才高中能做到这样非常不容易了。甭管东西质量好不好,拥有了一颗创新的心比什么都可贵。加油。

发表评论

你的邮件地址不会公开


*