基于树莓派(Raspberry Pi3)平台通过微信(WeChat模块)进行交互的智能家居实现

Posted 我的openresty

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于树莓派(Raspberry Pi3)平台通过微信(WeChat模块)进行交互的智能家居实现相关的知识,希望对你有一定的参考价值。

前言:


  其实做这个智能家居系统我还是因为学校的毕业设计,距离上篇文章发布已经过去了20多天了,之前想着只是做一个烟雾报警,然后通过Zabbix进行报警,但是通过这20多天的设计,我发现实现报警的功能其实除了邮件,还有短信、微信、甚至电话。但是因为各种原因,比如.....钱0.0,哈哈哈,因此我计划用企业微信进行一个报警,然后貌似通过普通微信进行一个简单的交互(interactive),还是不错的选择,并且做出来的效果也很棒。
  最后想说的是,下面文章如果有不正确的地方,还请多指正。

一、实现内容(重要) 

  前面我已经做了阐述,要做智能家居控制系统,除了实现各种报警之外,还要做到和Raspberry的交互,通过手机来控制它的输出,和执行相应的动作,还有最重要的一点,后面会用到运动识别检测。。。噢耶:)

1.实现目标

  下面是实现的具体目标,分三部分:交互端,报警端,摄像头运动物体检测报警端。

普通微信端交互控制:


企业微信端的报警:


家中运动物体识别检测报警:

2.注解

  这里我想大家解释一下我的计划组成部分:

①微信端交互功能。


  • camera # PiCamera拍照录像目录
  • face # 人脸识别目录
  • relay # 继电器模块测试目录
  • temp # 温湿度测控目录
  • weixin # 微信交互主文件目录
  • warning # 企业微信报警检测
  • Temp # 温湿度报警检测目录
  • Weixin_warning # 企业微信报警调用目录

  • 二、继电器功能实现

    1. 继电器模块简介


      继电器(英文名称:relay)是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器。它具有控制系统(又称输入回路)和被控制系统(又称输出回路)之间的互动关系。通常应用于自动化的控制电路中,它实际上是用小电流去控制大电流运作的一种“自动开关”。
      按照我的话说:继电器模块是通过Raspberry输入高低电平到IN口,来控制继电器的当中的电磁铁铁芯和衔铁的相互作用,当给线圈通电的时候,就会产生一个磁场,使得电磁铁铁芯被吸引到一个端口,从而实现端口的开路或者闭路,进而控制电器的开关。

    继电器靓照:


      官方简介:(便于后面的连线和理解原理)

    2. 三种工作原理介绍


      我在这里使用了一个模块,是松乐的SRD(T73)型号家用继电器,这里,分为三个端,依次是:“NO”,“COM”,“NC”,后面还有个“IN”端,用来连接树莓派的GPIO口,根据它输入的高低电平,来进行继电器的控制,也就是:


      这里有两种模式,常开,常闭。我经过测试以后,做了一个总结:


      不过这测试的结果好像颠覆了我的世界观。。。。。因为上面测试的结果,和前面对“常开端”和“常闭端”的定义好像正好相反,我也不知道为什么,可能是他们把线接反了吗?
    反正就是记着他的原理,然后用法就是这么用的就行了0.0
    总结:


    记住:给“IN”一个低电平就是使磁铁有磁性,改变当前单刀开关的位置

       为了方便,我后面会使用第二种连线方式,也就是“常闭”模式,为了保证安全!!!

    3. 继电器连线


      开始接线,我们的目的是要通过继电器控制家用电器,也就意味着需要把电线的两头接到继电器的两个端口,来通过控制继电器,从而控制两个端口是否是闭合还是断开,先上个图吧。

    3.1 I/O口连线及解释:


    这里放一个连接公共端和常开端的图:


      注意: 由于连接的是220V的电压,所以很具有危险性,因为闭合开关以后,继电器模块底部有一定的几率带电,所以尽量在下面垫一层纸板,用绝缘胶带缠上,通电以后,不要触摸,可以买一根电笔来测试连个端口是否有电。

    4. 命令行测试


      这里安排了一个简单的测试,是为了保证正确的连线,用到了一个软件wiringPi和上篇文章提到过的Python当中的RPi.GPIO库。

    4.1 wiringPi介绍:

      WiringPi 是应用于树莓派平台的 GPIO 控制库函数,WiringPi 遵守 GUN Lv3。wiringPi 使用 C 或者 C++ 开发并且可以被其他语言包转,例如 Python、ruby 或者 php 等。 wiringPi 包括一套 gpio 控制命令,使用 gpio 命令可以控制树莓派 GPIO 管脚。用户可以利用 gpio 命令通过 shell 脚本控制或查询 GPIO 管脚。

    4.2 wiringPi安装:

        ①  gpio readall     

      读取当前Raspberry的GPIO引脚情况。在这个地方可以查看40个的BCM编码规则;wPi编码规则;Name:引脚名称(有些I/O兼备多种功能的);Mode:模式,此时这个引脚是输入模式还是输出模式(默认开机的时候是输入模式),V:此时引脚的电平:“1”为高电平,“0”为低电平(大部分默认开机是低电平),可以看到图中方框圈住的是引脚,它是此时是输入模式并且是高电平。
    附图:

        ② gpio mode 11 out

      我采用了wPi编码规则,根据刚刚我上面的连线,我选取了IN2引脚,通过杜邦线把它接在了Raspberry的26号引脚上,就是中间的“Physical”物理引脚命名规则的26号引脚,而26号引脚对应的是wPi命名规则的“11”号引脚,然后用上面的命令设置该引脚为输出模式“OUT”,这样的话,才可以输出高低电平;相反要接收并且判断连在某个引脚上的电平是高电平还是低电平,那么就设置为输入模式“IN”,用来接收。这个地方大家一定要分清。
    附图:

        ③  gpio write  11 0

      向wPi命名规则的11号引脚输出一个低电平,然后就会发看到“V由1到0”,并且灯也亮了,状态灯也亮了,还有刀片的切换的声音,说明灯光打开成功啦。

    附图:


    状态灯图:

         # gpio write 11 1

      向wPi命名规则的11号引脚输出一个高电平,然后就会发看到“V由0到1”,并且插在插座上的灯灭了,同时状态灯也灭了,同样刀片有切换的声音,说明灯光关闭成功啦。

    附图:

         # gpio read 11

      可以读取刚刚定义好命名规则的引脚的状态,当然就是“0”或者“1”啦。
       附图:


      当你上面的都做出来的时候,那么恭喜你,成功地通过命令行的方式控制了连接在继电器模块上IN2引脚,到Raspberry的GPIO口的高低电平,进而控制了灯的开关,好像是不太难吧。。。只要按照我的连线,大家肯定可以做出来,并且可以多几次的输出高低电平,来感受继电器的工作原理和工作方式,并且熟悉这样命令行界面控制GPIO口的方式,很方便,很快可以的到一些结论,并且前面的对MQ-烟雾检测模块的测试,也可以通过上面的 gpio read 11 的命令来查看引脚状态。

    5. Python代码测试


      还是老样子,我使用的是Python3,通过调用RPo.GPIO库来实现在脚本当中,对GPIO的操作。

    5.1 程序段一

    #!/usr/bin/env python3
    import RPi.GPIO as GPIO
    import time
    
    relay = 40      # 采用BOARD编码,40号引脚,来控制继电器
    buzzer = 32   # 采用BOARD编码,32号引脚,来控制蜂鸣器
    GPIO.setmode(GPIO.BOARD)  # 声明BOARD编码规则
    GPIO.setwarnings(False)   
    GPIO.setup(relay, GPIO.OUT)     #  设置继电器的引脚为输出模式
    GPIO.setup(buzzer, GPIO.OUT)  #  设置蜂鸣器的引脚为输出模式

      ①对GPIO库进行一个引用,然后先定义引脚号,并且定义BOARD编码规则,这里需要看着前面的GPIO对应表,不要写错了,需要注意是当我们每次去执行完脚本以后,GPIO引脚有可能没有关闭调用,或者之前引脚在设定之前就是输出模式,要是再次定义它为输出模式,就会产生一个警告,很烦人,那么如何避免这个问题呢?就是中间的那条命令 GPIO.setwarnings(False) ,需要大家特别注意哦!

    5.2 程序段二

    j = 0
    while j<5:  
       GPIO.output(relay, GPIO.LOW)
       print ("灯亮了")
       GPIO.output(buzzer, GPIO.LOW)
       print ("蜂鸣器鸣响")
    
       time.sleep(3)  
    
       GPIO.output(relay, GPIO.HIGH)
       print ("灯关闭")
       GPIO.output(buzzer, GPIO.HIGH)
       print ("静默")
    
       time.sleep(3)

      ②这里进行了一个5次的程序执行,就拿出我们前面的结论:控制继电器,当给它一个低电平的时候,继电器模块的控制器则给它一个高电平,继电器内部线圈带电,产生磁场,导致单刀吸附到闭合那一端,这样上面我们接线的两个端口“COM”和“NO”就是通路了,就好像他俩没有被剪开一样,这个时候,灯就亮了,然后我设置了一个低电平给蜂鸣器,蜂鸣器也响了;后面则是给继电器IN2一个高电平,然后灯就关闭了,同时也给蜂鸣器一个高电平,蜂鸣器静默。
      相信大家也看到了,我进行了两次的睡眠 “time.sleep(3)” ,这是因为当进行了电平转换以后,一个是我们需要检验结果,所以有个状态驻留时间,尤其是最后的那个睡眠,记得必须加上,否则看不到效果,因为下次循环又转换为低电平,在这个期间,需要时间去让大家看出效果,就是灯是一直灭着的,同时也避免继电器瞬间切换产生的异常,要是大家感觉有些绕,可以自己进行一个实验,尝试去掉睡眠,这样也有助于你理解。

    三、温度传感器功能实现


      温度传感我觉得还是整个项目里比较有分量的,也是比较难的部分,这是为什么呢?其实大家可以在网上搜到很多关于温度传感器DHT11在Raspberry上的实现,有用Python写的,有用C写的,各种方法不尽相同,但是绝大部分都不够详细,比如程序当中有些语句 “while GPIO.input(channel_point) == GPIO.LOW:” 。这个就需要去结合DHT11模块本身的工作模式去理解,就会好很多,后面我会逐句一一进行讲解。

    1. DHT11简介


    附一张帅气的自拍:

    2. DHT11接线

    ①原理图:

       上面这张图是设计模块的使用说明电路图,很明显,在VCC和DATA需要并联一个电阻,貌似是需要做一个上拉电阻,来增加DATA的输出能力,并且图中是要求并联4K左右的电阻,但是实际测试得出结论,只要有2K就够了。


    ②虚拟连线图:

       红色的是电源线,连接在Raspberry的3.3V电源上,蓝色的是数据口DATA,黑色的是GND,就是按照上面图并联的电阻,不理解的多看看电路图。


    ③实际效果图:

       由于手头只有1K的电阻,所以简单的进行了一个串联,有些乱,但是这样连线,再跑程序就完全没有问题0.0。

    3. 驱动程序


       程序实现的过程还是比较简单的,但是需要结合DHT11的模块的说明来进行讲解,这样的解释程序的方式,相信大家读完会才可以更好的理解,希望仔细阅读这一部分。


       下面是产品公司对DHT11整个工作流程的时序图的概括,这其中包括了初始化操作。

    3.1 DHT11初始化(步骤一)

       官方原文:DHT11 上电后(DHT11 上电后要等待 1S 以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时 DHT11 的 DATA 数据线由上拉电阻拉高一直保持高电平;此时 DHT11 的DATA 引脚处于输入状态,时刻检测外部信号。

    #!/usr/bin/env python3
    
    import RPi.GPIO as GPIO
    import time
    
    def dht11(channel):
        channel_point = channel
        data = [ ]
    
        GPIO.setmode(GPIO.BOARD) # 设置编码格式
        time.sleep(1)

    3.2 DHT11初始化(步骤二)

       官方原文:微处理器的 I/O 设置为输出同时输出低电平,且低电平保持时间不能小于 18ms,然后微处理器的 I/O设置为输入状态,由于上拉电阻,微处理器的 I/O 即 DHT11 的 DATA 数据线也随之变高,等待DHT11 作出回答信号。

            GPIO.setup(channel_point, GPIO.OUT)    # 设置为输出
            GPIO.output(channel_point, GPIO.LOW)  # 输出一个低电平
            time.sleep(0.02)   # 睡眠0.02秒
            GPIO.output(channel_point, GPIO.HIGH)  # 输出一个高电平
            GPIO.setup(channel_point, GPIO.IN)         # 设置GPIO引脚为输入


       由于步骤二要求的是需要微处理器,也就是我们用的Raspberry,输出一个低电平,并且保持18ms以上,然后设置为输入模式,再把电平拉高,进行一个等待。

    3.3 DHT11初始化(步骤三)

       官方原文:DHT11 的 DATA 引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后 DHT11 的 DATA引脚处于输出状态,输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待 80 微秒
    的高电平后的数据接收。

        while GPIO.input(channel_point) == GPIO.LOW: 
            continue
        while GPIO.input(channel_point) == GPIO.HIGH: 
            continue

    3.4 DHT11采集数据

       官方原文:由 DHT11 的 DATA 引脚输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据,位数据“0”的格式为: 50 微秒的低电平和 26-28 微秒的高电平,位数据“1”的格式为: 50 微秒的低电平加 70
    微秒的高电平。
    位数据“0”、“1”的图两张:


       用我自己的话概括就是:经过上面的初始化以后,data开始发送数据,是40位的高低电平,也就是40位的“0”和“1”,然后开始发送数据了,位数据“0”的格式为:50微秒的低电平和26-28微秒的高电平,位数据“1”的格式为:50微秒的低电平和70微秒的高电平。

        data_number = 0                        # 设置计数器
        while data_number < 40:
                    high_time = 0                  # 统计 “while高电平循环”次数
                    while GPIO.input(channel_point) == GPIO.LOW:      # 接收一个50微秒的低电平
                                continue
                     while GPIO.input(channel_point) == GPIO.HIGH:  # 开始接收高电平
                                 high_time += 1                   # 开始对上面的while的循环次数进行计数
                                 if high_time> 100:              # 当循环次数超过100,退出本次循环
                                          break
    
                     if high_time < 8:                               # 对前面的while循环的次数进行判断
                                 data.append(0)                    # 如果小于8追加位数据“0”到字典当中
                      else:  
                                 data.append(1)                     # 大于8的追加位数据“1”到字典当中
                      data_number += 1                            # data_number自加1
    
        print("Modular is working.")
        print(data)

    3.5 DHT11数据计算

       前面通过对while循环次数的计算得出了data引脚输出的位数据是“0”还是“1”,并且全部追加到字典当中,下面开始对字典当中的值进行取出和计算。

       官方文档:数据格式:8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位。共40位,其中校验位是为了判断前面获取的温度和湿度是否数据由错误。

    对于这个40位的“0”和“1”,我们如何计算呢?下面给出了一个示例:


       上面用到的知识基本上就是2进制转换为10进制的操作,这里有个公式就是:就是2的次方乘以每个对应的0或者1,比如上面的温度的计算,“18H”就是先从二进制转换为16进制,24则是10进制;2的四次方 + 2的三次方=24,进制方面的知识可以去百度,但是必须要搞懂,因为下面的程序就是基于这个公式进行进制转换的。

     # 这里进行一个分片,一共40位的列表,先取出来前八个
        hum_bit = data[0:8]                    # 湿度高八位,其为整数位
        hum_decimal_bit = data[8:16]    # 湿度低八位,其为小数位
        temp_bit = data[16:24]                # 温度高八位,其为整数位
        temp_decimal_bit = data[24:32]  # 温度低八位,其为小数位
        check_bit = data[32:40]               # 校验位
    
    # 温湿度的初始值
        hum = 0
        hum_decimal = 0
        tem = 0
        temp_decimal = 0
        check = 0
    
    # 遍历字典当中的数据
        for i in range(8):
            hum += hum_bit[i] * 2 ** (7 - i)
            hum_decimal += hum_decimal_bit[i] * 2 ** (7 - i)
            tem += temp_bit[i] * 2 ** (7 - i)
            temp_decimal += temp_decimal_bit[i] * 2 ** (7 - i)
            check += check_bit[i] * 2 ** (7 - i)
    

       对于上面的遍历的公式:比如第六位的数字“1”,那是就用“1”去乘以2的5次方,因为它是从0开始的,所以到第六位就是“5”,也因此,后面算,也就是要减一位,也就有了上面的式子,认真理解。
    最后就算出来10进制的数据了,一共5个数据。

    3.6 DHT11数据整合判断

       这块儿程序是进行逻辑判断,如果有前四个数据加起来的 sum 的值不等于 check 校验位,那么说明数据有误,如果相同,说明数据是正常的,后面进行了数据的打印和整合。

        sum = hum + hum_decimal + tem+ temp_decimal
    
        info_dht11 = \'\'\' 温度:{0}.{1}°C  湿度:{2}.{3}\'\'\'.format(tem,temp_decimal,hum,hum_decimal )
        print(info_dht11)
        return check,sum,info_dht11
    
    if __name__ == \'__main__\':
        dht11(38)
        dht11(29)


       由于这个模块我是打算在后面把它作为一个微信交互程序调用的模块的,所以我的写法可能和前面叙述的不一样,我在这里说明一下,尤其是和校验位的比较,我放在了微信交互程序当中,为了把参数传到另一个文件的函数当中,我就运用了Python当中最伟大的发明 return ----一个可以返回任何值的关键字,我把这三个参数作为返回值传到微信交互函数当中,进行逻辑判断,并且温湿度的信息也一并传过去了。

    四、总结


     上面讲的只是用户微信需要的两个功能模块;后面我就开始讲Raspberry对PiCamera的调用,拍照,录像;对发来的照片进行简单的人脸识别;最后通过微信交互主程序对前面所有的功能进行统一调用,就完成了交互的全部功能。

       我会把上面所有实现的方法在后续写出来,就看这篇文章和下篇文章有多少人看了0.0....

    以上是关于基于树莓派(Raspberry Pi3)平台通过微信(WeChat模块)进行交互的智能家居实现的主要内容,如果未能解决你的问题,请参考以下文章

    从 BLE 设备接收数据到树莓派 Pi3

    Raspberry Pi 3 ~ C语言控制串口

    在树莓派 pi3 中安装 pip

    为树莓派 pi3 交叉编译 Qt 时出错

    树莓派(Raspberry Pi)FTP服务搭建

    如何为 Raspberry pi 3 编译 ARMv8 代码