最近天气很热,我租的房子又没有空调,基本上风扇一开就是一晚上,结果经常起床后发现口干舌燥的。我觉得这肯定是因为整晚吹风扇搞的,不管是不是,反正我觉得就是了。不开风扇吧,热!开风扇吧,早上起来不舒服,怎么办呢?能不能让风扇吹一会停一会这样的吹呢?让手机来当遥控器来控制风扇?加上语音控制?我看了下我那吃灰半年多的树莓派,觉得应该让它动一动了。
  
  硬件准备
  
  首先,电扇是必须的,树莓派吃灰了半年,也该工作工作了。其他再需要啥的就该淘宝了。树莓派控制电扇嘛,3v-7v直流信号控制220v交流的电磁继电器得一个。连接树莓派和继电器的杜邦线若干,连接电风扇和继电器得卡口一对,注意需要能承受住风扇的电流的,不要太细的。其他的以后再说吧!
  
  东西准备好后,先连接电路。PO上几张图,不用好看,只要能说明问题。
  
  拆掉底座后,图是这样的,左边是定时的,坏了定不了。右边是调速的。把调速的电源线断开,接到继电器得被控端。使用继电器的常闭触点,就是把树莓派拿掉,风扇和原来一样用。
  
  这里写图片描述这里写图片描述这里写图片描述这里写图片描述这里写图片描述
  
  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()
  
  从代码看也比较简单,使用GPIO05来控制风扇,默认设置为低电平。低电平的时候,继电器常闭,风扇的开关打开,风扇就转。高电平的时候,继电器的常闭触点断开,风扇开关打开的时候,风扇也不转了。输入open的时候,05脚设置为低电平,风扇打开。输入close的时候,05脚设置高电平,风扇停止。
  
  实现定时功能
  
  做这个的初衷就是让风扇定时开一会儿关一会儿,所以能控制风扇后,第一时间自然就是把这个功能给实现掉了。用python来实现,代码自然简单的不能再简单了:
  
  #-*- coding: utf-8 -*-
  
  from SmartServer import SmartServer
  
  import threading
  
  import RPi.GPIO as GPIO
  
  fanState=[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 www.qinlinyule.cn/ order:')
  
  时间校准及离家模式
  
  白天我不在家,风扇得保证不开,那首先得保证树莓派的时间正确。设置下定时更新网络上的时间,时区也得保证是我所用的时区,上海时区。
  
  # 安装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 * * * root ntpdate ntp.ubuntu.com
  
  然后我一般是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] www.yongshiyule178.com/ and now.tm_min<back[1]) or
  
  now.tm_hour<back[0]))
  
  编写服务器端接受指令
  
  运行程序后,风扇就一直按照既定的模式运行,开一会关一会好像也不太好,比如今天天气比较热,我回来的比较早,我想它先扇两个小时,然后再开半个小时,关十五分钟,这样循环怎么办?嗯,还是得有个遥控器,反正树莓派联了家里的网,一回来手机也是要联上Wifi,那就直接用手机来做遥控器了。
  
  想要手机控制树莓派,在树莓派上运行一个服务来接受来自手机的指令肯定是少不了的。一事不劳二主,依旧Python了。先写一个SmartServer的类,来创建服务器的Socket,来接受客服端的连接以及连接后的指令。
  
  #-*- coding: utf-8 -*-
  
  from socket import *
  
  from time import ctime
  
  from time import localtime
  
  import threading
  
  import time
  
  import datetime
  
  class SmartServer(object):
  
  """docstring for SmartServer"""
  
  HOST=''
  
  PORT=1122 #设置侦听端口
  
  BUFSIZ=1024 #buffer的大小
  
  SERVERFLAG=True
  
  fanSwitchTimestamp=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 www.feifanyule.cn/ 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( www.wmyl110.com target=server.openServer,args=())
  
  serverThread.setDaemon(True)
  
  serverThread.start()
  
  print('server thread start')
  
  serverThread.join (www.wmyL119.cn)
  
  写好后要确保它能正常工作,所以再写个客服端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, www.wmyL166.cn exit!')
  
  break
  
  print('从%s收到信息:%s' %(self.HOST,data.decode('utf8')))
  
  在树莓派上运行服务器,然后在另外一台电脑上运行客服端,运行结果如下。这样树莓派就可以接受来自局域网的控制指令了。
  
  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 (www.chuangyed.com );
  
  commands=new LinkedBlockingQueue <www.xingchexiu.com>();
  
  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=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();
  
  用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()
  
  这样手机也可以遥控电扇开关了。至于其他的更为复杂的,用手机设置定时时间,也就大同小异了,发送json过去,树莓派解析,然后完成设置进行控制就OK了。
  
  至此,风扇定时及android手机控制风扇的功能就OK了。

用树莓派改装电风扇及实现Android遥控的更多相关文章

  1. 我有DIY一Android遥控-所有开源

    我有DIY一Android遥控-所有开源 1.试用 记得宋宝华在「设备驱动开发具体解释」提出一个这种理论「软件和硬件互相渗透对方的领地」,这次证明还是确实是这样,使用上层APP软件加上简单的更为简单的 ...

  2. android手机卫士、3D指南针、动画精选、仿bilibli客户端、身份证银行卡识别等源码

    Android精选源码 android身份证.银行卡号扫描源码 android仿bilibili客户端 android一款3D 指南针 源码 android手机卫士app源码 android提醒应用, ...

  3. 树莓派开发板入门学习笔记2:[转]树莓派系统在VM中能做什么

    问"树莓派系统在VM中能做什么"不如问"树莓派能做什么":(参考:树莓派实验室) 普通难度的DIY 较高难度的DIY 用树莓派打造一个家庭影院 给树莓派安装摄像 ...

  4. 树莓派上搭建基于Python+web.py+fastcgi+lighttpd的网站

    最近在网上淘了一个树莓派,什么是树莓派?这里是他的官方网站你可以去看看. 简单的说就是一块使用了ARM11的CPU,具有256MB或512MB内存的具有两个USB接口,一个RJ45接口,HDMI输出和 ...

  5. 6410移植android4.4.2笔记(持续更新)

    如之前的android编译笔记里面描述,目前已经可以编译出armv7-neon的android镜像了,也就是说目前的环境以及aosp可以支持定制android程序了. 昨天晚上在device下面已经粗 ...

  6. 使用yocs_cmd_vel_mux进行机器人速度控制切换

    cmd_vel_mux包从名字就可以推测出它的用途,即进行速度的选择(In electronics, a multiplexer or mux is a device that selects one ...

  7. 树莓派+android things+实时音视频传输demo之遥控小车

    做了个测试小车,上面安装了摄像头,通过外网进行视频传输: https://www.bilibili.com/video/av23817880/

  8. StarRTC , AndroidThings , 树莓派小车,公网环境,视频遥控(三)手机端

    原文地址:http://blog.starrtc.com/?p=111 这篇来介绍一下整个项目的手机端部分.在上一篇里我们已经将sdk导入到项目中了,下边直接用即可. 1 登录StarRTC的服务跟小 ...

  9. StarRTC , AndroidThings , 树莓派小车,公网环境,视频遥控(二)小车端

    原文地址:http://blog.starrtc.com/?p=94 1 创建工程IDE:Android Studio 3.1:File>New>New Project>输入项目名& ...

随机推荐

  1. Scala学习(三)练习

    Scala数组相关操作&练习 1. 1. 编写一段代码,将a设置为一个包含n个随机整数的数组,要求随机数介于0(包含)和n(不包含)之间 def main (args: Array[Strin ...

  2. 闭包----你所不知道的JavaScript系列(4)

    一.闭包是什么? · 闭包就是可以使得函数外部的对象能够获取函数内部的信息. · 闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. · 闭包就 ...

  3. Mvc4_ @RenderBody、@RenderPage、@RenderSection用法

    一.@RenderBody 当创建基于_Layout.cshtml布局页面的视图时,视图的内容会和布局页面合并,而新创建视图的内容会通过_Layout.cshtml布局页面的@RenderBody() ...

  4. TRIO-basic变量的状态位

    TRIO运动控制器在应用中,我们一般会用一个VR寄存器的状态位来控制一些报警信号,这样有利于代码的优化,同时和触摸屏设置报警信息大大的方便和节约时间. 首先测试了一下一个寄存器可以设置多少个状态位. ...

  5. Linux下环境变量配置方法梳理(.bash_profile和.bashrc的区别)

    在linux系统下,如果下载并安装了应用程序,在启动时很有可能在键入它的名称时出现"command not found"的提示内容.如果每次都到安装目标文件夹内,找到可执行文件来进 ...

  6. Docker容器学习梳理 - 容器登陆方法梳理(attach、exec、nsenter)

    对于运行在后台的Docker容器,我们运维人员时常是有登陆进去的需求.登陆Docker容器的方式:1)使用ssh登陆容器.这种方法需要在容器中启动sshd,存在开销和攻击面增大的问题.同时也违反了Do ...

  7. Redis常用操作-----字符串

    1.APPEND key value 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾. 如果 key 不存在, APPEND 就简单地将给定 ...

  8. Python-复习-习题-13

    复习 dict: dic = {'name':'alex'}增:dic['age'] = 21 存在就覆盖dic.setdefault() 存在什么也不做,没有就增加 删除:pop()按照key删除, ...

  9. #个人作业Week2——结对编程对象代码复审

    General 代码能够正确运行,能够正确生成指定数量的题目和答案,并且能够对给出的题目和答案文件进行比对,输出结果. 代码没有非常复杂的逻辑,比较容易理解,但是在缺少注释的情况下有部分代码需要较长时 ...

  10. 2-Twentieth Scrum Meeting-20151220

    任务安排 成员 今日完成 明日任务 闫昊 请假(数据库)   唐彬 请假(数据库)   史烨轩  尝试使用downloadmanager对notification进行更新  尝试使用downloadm ...