用树莓派改装电风扇及实现Android500.gs遥控

博观而约取,厚积而薄发。这篇文章主要讲述用树莓派改装电风扇及实现Android500.gs遥控相关的知识,希望能为你提供帮助。
【用树莓派改装电风扇及实现Android500.gs遥控】最近天气很热,我租的房子又没有空调,基本上风扇一开就是一晚上,结果经常起床后发现口干舌燥的。我觉得这肯定是因为整晚吹风扇搞的,不管是不是,反正我觉得就是了。不开风扇吧,热!开风扇吧,早上起来不舒服,怎么办呢?能不能让风扇吹一会停一会这样的吹呢?让手机来当遥控器来控制风扇?加上语音控制?我看了下我那吃灰半年多的树莓派,觉得应该让它动一动了。
硬件准备首先,电扇是必须的,树莓派吃灰了半年,也该工作工作了。其他再需要啥的就该淘宝了。树莓派控制电扇嘛,3v-7v直流信号控制220v交流的电磁继电器得一个。连接树莓派和继电器的杜邦线若干,连接电风扇和继电器得卡口一对,注意需要能承受住风扇的电流的,不要太细的。其他的以后再说吧! 
东西准备好后,先连接电路。PO上几张图,不用好看,只要能说明问题。 
拆掉底座后,图是这样的,左边是定时的,坏了定不了。右边是调速的。把调速的电源线断开,接到继电器得被控端。使用继电器的常闭触点,就是把树莓派拿掉,风扇和原来一样用。 

用树莓派改装电风扇及实现Android500.gs遥控

文章图片
用树莓派改装电风扇及实现Android500.gs遥控

文章图片
用树莓派改装电风扇及实现Android500.gs遥控

文章图片
用树莓派改装电风扇及实现Android500.gs遥控

文章图片
用树莓派改装电风扇及实现Android500.gs遥控

文章图片

GPIO控制风扇编写Python代码,来控制风扇开关,测试一下GPIO。这个是控制的基础,要是这步走不通,后续就没意义了。
#-*- coding: utf-8 -*- import RPi.GPIO as GPIO# gpio初始化 def gpioInit(): GPIO.setmode(GPIO.BCM) GPIO.setup(5,GPIO.OUT,initial=GPIO.LOW)# 风扇是GPIO05 def switchFan(open): GPIO.output(5,open) print(‘fan open‘ if open==0 else ‘fan close‘)if __name__ == ‘__main__‘: order=‘a‘ gpioInit() while order!=‘exit‘: order=input(‘input you order:‘) if order==‘open‘: switchFan(0) elif order==‘close‘: switchFan(1) else: print(‘bad order‘) GPIO.cleanup() print(‘smart exit!‘)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
从代码看也比较简单,使用GPIO05来控制风扇,默认设置为低电平。低电平的时候,继电器常闭,风扇的开关打开,风扇就转。高电平的时候,继电器的常闭触点断开,风扇开关打开的时候,风扇也不转了。输入open的时候,05脚设置为低电平,风扇打开。输入close的时候,05脚设置高电平,风扇停止。
实现定时功能做这个的初衷就是让风扇定时开一会儿关一会儿,所以能控制风扇后,第一时间自然就是把这个功能给实现掉了。用python来实现,代码自然简单的不能再简单了:
#-*- coding: utf-8 -*- from SmartServer import SmartServer import threading import RPi.GPIO as GPIOfanState=[1]# gpio初始化 def gpioInit(): GPIO.setmode(GPIO.BCM) GPIO.setup(5,GPIO.OUT,initial=GPIO.HIGH)# 风扇是GPIO02 def switchFan(open=[0]): fanState[0]= 1 if not open[0] else 0 GPIO.output(5,fanState[0]) print(‘fan close‘ if fanState[0] else ‘fan open‘)# 定时任务,默认十五分钟执行一次 def timerCheck(time=60*15,func=0,args=()): if func: func(args) timer=threading.Timer(time,timerCheck,(time,func,args)) timer.start()if __name__ == "__main__": gpioInit() # 十五分钟反转一下GPIO,开启时风扇是打开的 timerCheck(time=60*15,func=switchFan,args=(fanState)) print(‘now fanState :‘,fanState) order=‘‘ while order!=‘exit‘: order=input(‘input you order:‘) GPIO.cleanup()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
时间校准及离家模式白天我不在家,风扇得保证不开,那首先得保证树莓派的时间正确。设置下定时更新网络上的时间,时区也得保证是我所用的时区,上海时区。
# 安装ntpdate apt-get install ntpdate # 选择时区 sudo tzselect # 然后选择亚洲 Asia-> 中国(China)-> 北京(Beijing) # 接着复制到etc下 cp /usr/share/zoneinfo/Asia/Shanghai/etc/localtime # 更新时间,会得到正确时区的服务器时间 sudo ntpdate ntp.ubuntu.com # 每天校准,添加到定时任务里面去 vi /etc/crontab # 加入下面这个,每天6点十分校准 # 10 6* * *rootntpdate ntp.ubuntu.com

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
然后我一般是7:30离家上班去,9:30左右回到家,所以在这个区间,如果我忘记关风扇了,它也应该保证不开,只要判断这个时间段就OK了:
# 判断当前是否离家了 def isLeave(leave=[7,30],back=[21,30]): now=time.localtime(time.time()) return not (((now.tm_hour==leave[0] and now.tm_min> =leave[1]) or now.tm_hour> leave[0]) and ((now.tm_hour==back[0] and now.tm_min< back[1]) or now.tm_hour< back[0]))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
编写服务器端接受指令运行程序后,风扇就一直按照既定的模式运行,开一会关一会好像也不太好,比如今天天气比较热,我回来的比较早,我想它先扇两个小时,然后再开半个小时,关十五分钟,这样循环怎么办?嗯,还是得有个遥控器,反正树莓派联了家里的网,一回来手机也是要联上Wifi,那就直接用手机来做遥控器了。 
想要手机控制树莓派,在树莓派上运行一个服务来接受来自手机的指令肯定是少不了的。一事不劳二主,依旧python了。先写一个SmartServer的类,来创建服务器的Socket,来接受客服端的连接以及连接后的指令。
#-*- coding: utf-8 -*- from socket import * from time import ctime from time import localtime import threading import time import datetimeclass SmartServer(object): """docstring for SmartServer"""HOST=‘‘ PORT=1122#设置侦听端口 BUFSIZ=1024 #buffer的大小 SERVERFLAG=TruefanSwitchTimestamp=0#风扇上次状态切换时候的时间 fanState=0#风扇当前状态 fanForceClose=True#是否强制关闭风扇,离家的时候def __init__(self): super(SmartServer, self).__init__()def clientSocketDoWhat(self,client,address,clientId): while True: try: data=client.recv(self.BUFSIZ) except Exception as e: print(‘error when recv data from client!‘) break if not data: break #python3使用bytes,所以要进行编码 #s=‘%s发送给我的信息是:[%s] %s‘ %(addr[0],ctime(), data.decode(‘utf8‘)) #对日期进行一下格式化 ISOTIMEFORMAT=‘%Y-%m-%d %X‘ stime=time.strftime(ISOTIMEFORMAT, localtime()) s=‘getIt %d , %s‘ %(clientId,data.decode(‘utf8‘)) client.send(s.encode(‘utf8‘)) print([clientId],[stime], ‘:‘, data.decode(‘utf8‘)) #如果输入quit(忽略大小写),则程序退出 quit=(data.decode(‘utf8‘).upper()=="QUIT") if quit: break client.close()def openServer(self,host=‘‘,port=1122,bufsize=1024): self.HOST=host self.PORT=port self.BUFSIZ=bufsize ADDR=(self.HOST, self.PORT) sock=socket(AF_INET, SOCK_STREAM) sock.bind(ADDR) sock.listen(5) print(‘Server start‘) while self.SERVERFLAG: print(‘等待接入,侦听端口:%d‘ % (self.PORT)) tcpClientSock, addr=sock.accept() print(‘接受连接,客户端地址:‘,addr) clientId=int(time.time()); print(‘分派给客户端的ID:%d‘%(clientId)) th=threading.Thread(target=SmartServer.clientSocketDoWhat,args=(self,tcpClientSock,addr,clientId,)) th.setDaemon(True) th.start() sock.close()# 测试代码 if __name__ == "__main__": server=SmartServer() serverThread=threading.Thread(target=server.openServer,args=()) serverThread.setDaemon(True) serverThread.start() print(‘server thread start‘) serverThread.join()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
写好后要确保它能正常工作,所以再写个客服端client.py:
#-*- coding: utf-8 -*- from socket import *class TcpClient: #测试,连接服务器 HOST=‘192.168.1.102‘ #设置侦听端口 PORT=1122 BUFSIZ=1024 ADDR=(HOST, PORT) def __init__(self): self.client=socket(AF_INET, SOCK_STREAM) self.client.connect(self.ADDR)while True: data=input(‘> ‘) if not data: break #python3传递的是bytes,所以要编码 self.client.send(data.encode(‘utf8‘)) print(‘发送信息到%s:%s‘ %(self.HOST,data)) if data.upper()=="QUIT": break data=self.client.recv(self.BUFSIZ) if not data: print(‘no info from server, exit!‘) break print(‘从%s收到信息:%s‘ %(self.HOST,data.decode(‘utf8‘)))if __name__ == ‘__main__‘: client=TcpClient()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
在树莓派上运行服务器,然后在另外一台电脑上运行客服端,运行结果如下。这样树莓派就可以接受来自局域网的控制指令了。
android端遥控器树莓派的服务器端已经准备好了,并且测试通过了,那下一步就是来做个客户端。其实也看的出来,Android端的代码会比较简单,写个Socket连接上树莓派,发送指令基本就OK了。主要代码如下:
public class SmartClient implements Runnable{private UserConfig config=UserConfig.getInstance(); private boolean socketFlag=false; private Gson gson; private String charSet="utf-8"; private byte[] dataFromServer=new byte[2048]; private Thread mThread; private Socket mSocket; private LinkedBlockingQueue< Command> commands; public SmartClient(){ gson=new GsonBuilder().create(); commands=new LinkedBlockingQueue< > (); mThread=new Thread(this); }public void connectServer(){ socketFlag=true; mThread.start(); }private void connectToServer() throws IOException { Log.e("wuwang","try connect to socket"+config.getIp()+":"+config.getPort()); mSocket=new Socket(); mSocket.connect(new InetSocketAddress(config.getIp(),config.getPort())); Log.e("wuwang","try connect to socket"); while (!mSocket.isClosed()& & socketFlag){OutputStream stream=mSocket.getOutputStream(); try { Command command=commands.poll(20, TimeUnit.SECONDS); if(command==null) { stream.write("{}".getBytes(charSet)); }else{ stream.write(gson.toJson(command).getBytes(charSet)); } } catch (InterruptedException e) { e.printStackTrace(); continue; } InputStream in=mSocket.getInputStream(); int result=in.read(dataFromServer); if(result> 0){ String value=https://www.songbingjia.com/android/new String(dataFromServer,0,result); Log.e("wuwang","dataFromServer::"+value); } }}public void addCommand(Command command){ commands.offer(command); }public void addCommand(int type,int value){ Command c=new Command(); c.type=type; commands.offer(c); }@Override public void run() { try { connectToServer(); } catch (IOException e) { e.printStackTrace(); } }public void close(){ socketFlag=false; if(mSocket!=null){ try { mSocket.close(); } catch (IOException e) { e.printStackTrace(); } } try { mThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
用Json来通信,来方便后面的扩展,用type来表示命令的类型,先做简单的,type为1表示强制打开风扇,type为0表示强制关闭。当然,控制端发送给树莓派后,树莓派需要解析出来,然后根据控制命令执行才行。增加解析这个type的来执行的代码到clientSocketDoWhat中,self.fanControl为测试gpio时的switchFan方法:
def clientSocketDoWhat(self,client,address,clientId): while self.SERVERFLAG: try: data=client.recv(self.BUFSIZ) except Exception as e: print(‘error when recv data from client!‘) break if not data: break #python3使用bytes,所以要进行编码 #s=‘%s发送给我的信息是:[%s] %s‘ %(addr[0],ctime(), data.decode(‘utf8‘)) #对日期进行一下格式化 ISOTIMEFORMAT=‘%Y-%m-%d %X‘ stime=time.strftime(ISOTIMEFORMAT, localtime()) s=‘getIt %d , %s‘ %(clientId,data.decode(‘utf8‘)) client.send(s.encode(‘utf8‘)) print([clientId],[stime], ‘:‘, data.decode(‘utf8‘)) command=json.loads(data.decode(‘utf8‘)) type=command.get(‘type‘,-1) if type==1 : if self.fanControl: self.fanControl([1]) elif type==0: if self.fanControl: self.fanControl([0]) #如果输入quit(忽略大小写),则程序退出 quit=(data.decode(‘utf8‘).upper()=="QUIT") if quit: break client.close()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
这样手机也可以遥控电扇开关了。至于其他的更为复杂的,用手机设置定时时间,也就大同小异了,发送json过去,树莓派解析,然后完成设置进行控制就OK了。
至此,风扇定时及android手机控制风扇的功能就OK了。





    推荐阅读