前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >基于人体红外热释电检测的树莓派邮件报警器

基于人体红外热释电检测的树莓派邮件报警器

作者头像
聪明的瓦肯人
修改于 2020-02-26 12:54:51
修改于 2020-02-26 12:54:51
1.5K00
代码可运行
举报
文章被收录于专栏:工科生日常工科生日常
运行总次数:0
代码可运行

只要标题够唬人,你们就会点进来,内容什么的其实都无所谓,无聊已经逼迫帅气的我做出了这种东西?!

——聪明的瓦肯人

01

写在前面

在一个闲人免进的地方

老板恰巧少了一个摄像头

这个时候

你就可以帅气的出场

带着这款高端大气上档次的

树莓派邮件报警器

承担起临时重任

系统的核心

其实就是python邮件收发功能

使用的是SMTP与POP3协议

配合外设人体红外传感器

实现人员检测警报

02

说说硬件

正如封面所示

硬件也就这样

左边是树莓派3B+单板微型电脑

搭载Arm架构的博通CPU

右边白色圆状物体就是

人体红外热释电传感器

红色杜邦线是正极VCC

蓝色杜邦线是负极GND

黄线是信号线,信号为3.3V

再次检测的封锁时间默认为2.5s

检测到人后延迟信号时间默认为0.5s

面包板上

下面的红色LED是人员检测信号灯

上面的红色LED是闪烁驱离警报灯

当然你也可以添加蜂鸣警报器,喇叭等等

在这里只是做一个演示

所以器件简单

现在

我们来聊聊这个人体红外传感器

人体红外热释电传感器,利用的是人体37摄氏度体温所发出的大约9~10微米的红外线,通过菲涅尔透镜(正上方图)聚焦在热释电元件上,热释电元件一般由单晶、压电陶瓷、高分子薄膜制成,其遇热会在晶体两端产生电荷相反数量相等的电荷。

该传感器有两个热释电元件,但是极性相反串联,正常情况下两热释电元件自发极化产生的或是环境温度变化产生的电荷会相互抵消而不会放电产生信号,巧妙的设计大大加强了它的抗干扰能力。

只有当人体移动时,两元件接收的热能不相等,导致极化电流不相等,无法抵消,从而输出电流信号;当人体静止时,电流消耗完毕,温度也不再变化,两元件处于平衡状态,信号消失;需要注意的是,突然的阳光照射会导致电荷不平衡而输出信号等等。

简而言之,任何造成两元件受热不一致的情况,都会造成传感器放电直至电荷消耗完毕。

03

看看软件

正所谓

python在手,天下我有

本次依然使用优雅的python编程

代码在树莓派中编写运行

这意味着

你得首先会树莓派基本操作

烧录镜像系统,远程登录等等

主要用到

SMTP发邮件,POP3收邮件

所以你需要两个邮箱

需要注意的是

无论是SMTP还是POP3

都是在使用第三方操纵邮件

以QQ邮箱为例

你需要在代码中写入口令

而这个口令并不是你的邮箱密码

你可以在你的邮箱后台获得

具体信息可以百度查得

多线程实现收发检测警报“同时”进行

调用GPIO模块操控树莓派IO口

总的来说

是一次python基础大测验

话不多说

上代码

(有注释哦)

邮件警报:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#date:2020/02/20
#name:send_mail.py
#作者:聪明的瓦肯人
#微信公众号:工业光线
#网站:http://www.tech-xjc.com

#导入树莓派GPIO模块
import RPi.GPIO as GPIO
#导入发邮件相关模块
from email import encoders
from email.header import Header
from email.utils import parseaddr, formataddr
from email.mime.text import MIMEText
import smtplib
import time

#设置GPIO口引脚编号为BOARD模式
GPIO.setmode(GPIO.BOARD)
#设置7号引脚为输入模式,默认拉低电平
GPIO.setup(7,GPIO.IN,pull_up_down=GPIO.PUD_DOWN)
#设置16号引脚为输出模式,默认低电平
GPIO.setup(16,GPIO.OUT,initial=GPIO.LOW)

msg = MIMEText("警告:\n非法人员闯入!请立即采取相关措施!", 'plain', 'utf-8')
# 输入Email地址和口令:
from_addr ='16******81@qq.com'
password_smtp ='qnfs********bacj'
# 输入收件人地址:
to_addr4 = '34******84@qq.com'
# 输入SMTP服务器地址:
smtp_server = 'smtp.qq.com'

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

#构造头部From信息
msg['From'] = _format_addr('树莓派邮件警报器 <%s>' % from_addr)
#构造头部Subject信息
msg['Subject'] = Header('Alert from raspberry pi', 'utf-8').encode()

#连接SMTP服务器
server_smtp = smtplib.SMTP(smtp_server, 25) # SMTP协议默认端口是25
#是否显示调试信息,1显示,0不显示
server_smtp.set_debuglevel(0)
#登录
server_smtp.login(from_addr, password_smtp)

def check_send_alert():
#轮询7号引脚状态,高电平触发邮件发送
    while True:
        state = GPIO.input(7)
        GPIO.output(16,state)
        if state == 1:
            server_smtp.sendmail(from_addr,to_addr4, msg.as_string())
            print('\n*****已发送警报邮件!*****')
            #1分钟后再检测状态,是否再次发送邮件
            time.sleep(60)

人体红外传感器信号口接在7号GPIO

通过下面这句检测7号IO口状态

这种方法需要通过循环遍历

来实时监测

比较消耗资源

当然也可以检测电平边沿

来减少资源的使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
state = GPIO.input(7)

高电平有人,低电平无人

之后会收到警报邮件

邮件接收与处理:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#name:email_alert_system.py
#date:2020/02/20
#作者:聪明的瓦肯人
#微信公众号:工业光线
#网站:http://www.tech-xjc.com

#导入自己的邮件报警模块send_mail
import send_mail

#导入树莓派GPIO模块
import RPi.GPIO as GPIO
import time
import threading

#导入POP3收邮件相关模块
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
import poplib

#设置GPIO引脚编号模式为BOARD
GPIO.setmode(GPIO.BOARD)
#设置11号引脚为输出,初始化为低电平
GPIO.setup(11,GPIO.OUT,initial=GPIO.LOW)

#task变量用于存储消息,并在thread1线程中作出判断
task = ''
#收邮件地址,口令与POP3服务器
email = '16******81@qq.com'
password_pop3 = 'qnfs*********acj'
pop3_server = 'pop.qq.com'
#guess_charset用于解析邮件的编码格式,要根据不同的编码进行解码
def guess_charset(msg):
    charset = msg.get_charset()
    print(charset)
    if charset is None:
        content_type = msg.get('Content-Type','').lower()
        pos = content_type.find('charset=')
        if pos >= 0:
            charset = content_type[pos + 8:].strip()
            print(charset)
    return charset

#decode_str用于解码邮件头部信息字符
def decode_str(s):
    value,charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value

#根据邮件类型解析内容并打印
def print_info(msg,indent=0):
    if indent == 0:
        for header in ['From','To','Subject']:
            value = msg.get(header,'')
            if value:
                if header == 'Subject':
                    value = decode_str(value)
                else:
                    hdr,addr = parseaddr(value)
                    name = decode_str(hdr)
                    value = u'%s <%s>' % (name,addr)
            print('%s%s:%s' % (' ' * indent,header,value))
    #判断邮件是否为multipart类型,粗略的理解为复合消息(比如text与html)
    if (msg.is_multipart()):
        parts = msg.get_payload()
        #将不同内容编码分块,并重新执行print_info递归一直到part不再是multipart类型
        for n,part in enumerate(parts):
            print('%spart %s' % (' ' * indent,n))
            print('%s-------------------' % (' ' * indent))
            print_info(part,indent + 1)
    #part不再是multipart则执行else
    else:
        content_type = msg.get_content_type()
        if content_type=='text/plain' or content_type=='text/html':
            #获取内容
            content = msg.get_payload(decode=True)
            #解析编码类型
            charset = guess_charset(msg)
            if charset:
                #根据编码类型进行解码
                content = content.decode(charset)
                if content_type=='text/plain':
                    global task
                    task = content
            print('%sText:%s' % (' ' * indent,content))

#灯光闪烁驱离函数
def light_blinker():
    while True:
        if task == '闪烁驱离':
            #1是高电平,0是低电平
            GPIO.output(11,1)
            time.sleep(0.5)
            GPIO.output(11,0)
            time.sleep(0.5)
            print('\n正在闪烁驱离!')
        if task == '停止闪烁':
            GPIO.output(11,0)
            print('\n已停止闪烁!')
            time.sleep(1)
            
#连接到POP3服务器,注意QQ需要SSL加密
server_pop3 = poplib.POP3_SSL(pop3_server,port=995)
#是否显示调试信息,0是关,1是开
server_pop3.set_debuglevel(0)
#打印POP3欢迎消息
print(server_pop3.getwelcome().decode('utf-8'))
#身份认证
server_pop3.user(email)
server_pop3.pass_(password_pop3)
#返回邮件编号
resp,mails,octets = server_pop3.list()
index_former = len(mails)

def get_mail():
    while True:
        #打印邮件数量与大小
        #print('Messages:%s.Size:%s'% server.stat())
        resp,mails,octets = server_pop3.list()
        index_now = len(mails)
        #根据邮件数量差值判断是否有新邮件
        new_msg = index_now - index_former
        global index_former
        index_former = index_now
        #获取最新邮件,lines中存储了最新邮件原始文本的所有行
        resp,lines,octets = server_pop3.retr(index_now)
    
        if new_msg > 0:
            print('********************************************************')
            print('\n有一封新邮件!')
            print(mails)
            #msg_content存储了邮件的原始信息,以回车相连(str)
            msg_content = b'\r\n'.join(lines).decode('utf-8')
            print('--------------------------------------------------------')
            #通过parsestr将msg_content转换为email类
            msg = Parser().parsestr(msg_content)
            print(msg)
            print('--------------------------------------------------------')
            print_info(msg)
            print(task)
            print('********************************************************')
            if task == '停机':
                break

#新建线程thread1,thread2
thread1 = threading.Thread(target=light_blinker,name='blinker')
#设置thread1为守护线程
thread1.setDaemon(True)
thread2 = threading.Thread(target=send_mail.check_send_alert,name='alert')
thread2.setDaemon(True)
thread3 = threading.Thread(target=get_mail,name='getMail')
thread1.start()
thread2.start()
thread3.start()
thread3.join()
#退出循环,解除服务
server_pop3.quit()
send_mail.server_smtp.quit()
#释放GPIO口资源
GPIO.cleanup()
print('**********已停机!**********')

实际上

如果你看懂了代码

你可能会觉得我多此一举

因为POP3收邮件指令

根本无需读取邮件内容

读取邮件内容还需判断是否为multipart类型

大大增加了复杂度

仅仅是获取简单指令

只需要解析邮件头部subject主题即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#decode_str用于解码邮件头部信息字符
def decode_str(s):
    value,charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value

#根据邮件类型解析内容并打印
def print_info(msg,indent=0):
    if indent == 0:
        for header in ['From','To','Subject']:
            value = msg.get(header,'')
            if value:
                if header == 'Subject':
                    value = decode_str(value)
                else:
                    hdr,addr = parseaddr(value)
                    name = decode_str(hdr)
                    value = u'%s <%s>' % (name,addr)
            print('%s%s:%s' % (' ' * indent,header,value))

这种想法也没错

但读取邮件内容可以获得复杂信息

也就意味着可以进行更复杂的控制

当然

在这里确实有点大材小用

这里全当练手了 在创建线程方面

主线程用于创建子线程

并等待线程3退出

将线程1和2设为守护线程

等待线程3结束

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
thread3.join()

线程3会在收到邮件指令后退出

非守护线程3退出后

守护线程全部退出

并停止邮件收发服务

系统停机

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#新建线程thread1,thread2
thread1 = threading.Thread(target=light_blinker,name='blinker')
#设置thread1为守护线程
thread1.setDaemon(True)
thread2 = threading.Thread(target=send_mail.check_send_alert,name='alert')
thread2.setDaemon(True)
thread3 = threading.Thread(target=get_mail,name='getMail')
thread1.start()
thread2.start()
thread3.start()
thread3.join()
#退出循环,解除服务
server_pop3.quit()
send_mail.server_smtp.quit()

需要注意的是

这里有一个坑

如果你使用IDLE运行程序

线程1和2不会退出

因为IDLE默认悄悄开启一个线程

但你会发现LED已经不亮了

那是因为线程3退出后

主线程运行了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#释放GPIO口资源
GPIO.cleanup()

最后

来看看运行效果吧

我想了想,还是应该好好写,不能乱搞,最近要忙毕设了,在什么山上唱什么歌,各位好汉,咱们下次见!byebye~

——聪明的瓦肯人

• end •

1.本文遵守CC BY-NC-SA 4.0知识共享版权协议 2.本文未加水印图片来自网络,侵删

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 工科生日常 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Linux环境搭建系列(2) —— MySQL 的安装
由于不同的 Linux 版本对应着不同的的 MySQL 版本,因此我们需要先找到适合我们所安装的 Linux 操作系统。在这里我将以 ContOS 7.5 为例,开始在 Linux 上安装与配置 MySQL。
求和小熊猫
2020/11/25
7220
Linux环境搭建系列(2) —— MySQL 的安装
Centos 7离线安装mysql5.7.18
1.查看已安装MariaDB相关的包              rpm -qa | grep mariadb
阿木木
2023/08/08
5540
centos7 安装 mysql 详解
下载地址 : https://dev.mysql.com/downloads/mysql/
IT小马哥
2020/03/18
1.2K0
Linux系统安装MySQL的详细步骤
(图片来自:https://www.cnblogs.com/gpdm/p/7170521.html)
问问计算机
2021/05/08
5.2K0
Linux系统安装MySQL的详细步骤
CentOS7下安装MySQL教程(rpm方式)
wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.22-1.el7.x86_64.rpm-bundle.tar
吾非同
2021/08/05
1.3K0
Linux系统:Centos7安装Jdk8、Tomcat8、MySQL5.7环境
yum源中默认启用的安装包版本为MySQL8.0,这里切换为5.7,执行以下命令;
知了一笑
2019/07/19
9210
centos7下安装mysql5.7(rpm)「建议收藏」
可以选择 RPM Bundle,下载完记得解压 tar -xvf xxx.tar
全栈程序员站长
2022/08/11
1.4K0
centos7下安装mysql5.7(rpm)「建议收藏」
centeros7安装mysql
新建目录 mkdir ~/mysql cd ~/mysql 下载mysql wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.26-1.el7.x86_64.rpm-bundle.tar 安装mysql tar -xvf mysql-5.7.26-1.el7.x86_64.rpm-bundle.tar #输出 #mysql-community-embedded-devel-5.7.26-1.el7.x86_64.rpm #mysql-c
用户4584874
2020/07/29
1.2K0
centeros7安装mysql
centos7安装mysql(完整)
官网5.7版本:https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.29-1.el7.x86_64.rpm-bundle.tar
执笔记忆的空白
2020/12/24
1.1K0
centos7下rpm安装mysql5.7
1.wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.22-1.el7.x86_64.rpm-bundle.tar 2.按照依赖关系依次安装rpm包 依赖关系依次为common→libs→client→server
@凌晨
2020/07/13
1.2K0
CentOS 7 安装 MySQL 5.7
官网下载地址:http://dev.mysql.com/downloads/mysql/
OY
2022/03/17
9050
CentOS 7 安装 MySQL 5.7
Linux离线安装MySQL5.7.24
官方地址:https://downloads.mysql.com/archives/community/
静谧星空TEL
2022/05/10
2.2K1
Linux离线安装MySQL5.7.24
Linux安装MySQL5.7.24
官方地址:https://downloads.mysql.com/archives/community/
静谧星空TEL
2021/04/27
5970
Linux安装MySQL5.7.24
无外网环境下CentOS 7安装MySQL 5.7.18
以上四个rpm包是必须的,如果还需要其他的功能,可以自行进行下载。以当前版本为例,包含全部的rpm包的文件为mysql-5.7.18-1.el7.x86_64.rpm-bundle.tar。
阿dai学长
2019/04/03
1.9K0
CentOS7.2下安装MySQL-5.7.18RPM Bundle版(适用于最新版5.7.20)
版权声明:本文为耕耘实录原创文章,各大自媒体平台同步更新。欢迎转载,转载请注明出处,谢谢。
耕耘实录
2018/12/20
1K0
Linux下mysql的安装与配置
1、在 Centos7 系统下使用 yum 命令安装 MySQL,需要注意的是 CentOS 7 版本中 MySQL数据库已从默认的程序列表中移除,所以在安装前我们需要先去官网下载 Yum 资源包,下载地址为:https://dev.mysql.com/downloads/repo/yum/
菲宇
2022/12/21
7150
Mysql5.7 rpm离线安装
下载rpm bundle包 https://mirrors.tuna.tsinghua.edu.cn/mysql/downloads/MySQL-5.7/mysql-5.7.32-1.sles12.x86_64.rpm-bundle.tar 卸载CentOS7系统自带的mariadb > rpm -qa|grep mariadb > rpm -e --nodeps mariadb-libs-5.5.60-1.el7_5.x86_64 安装依赖 > yum install perl* cpan net-
入门笔记
2022/06/02
1.3K0
手把手教你部署一套生产级的 mysql 数据库
实际的软件项目开发过程中,不可避免的需要用到关系型数据库,比较主流的关系型数据库有 mysql、oracle、sql server、postgresql、db2 等等,当然目前最主流的数据库非 mysql 莫属,相比其他数据库,mysql 性能可靠,使用简单,而且开源免费。
Java极客技术
2022/12/04
9840
手把手教你部署一套生产级的 mysql 数据库
Linux MySQL下载安装详细教程(CentOS版)
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle旗下产品。MySQL是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的RDBMS (Relational Database Management System,关系数据库管理系统)应用软件之一。本文将介绍Linux CentOS环境下安装MySQL 8+,采用npm安装包方式安装
Jensen_97
2023/12/19
2.7K0
Linux MySQL下载安装详细教程(CentOS版)
Centos7 离线安装MySQL
下载地址:https://dev.mysql.com/downloads/mysql/
你好戴先生
2020/09/02
1.9K0
相关推荐
Linux环境搭建系列(2) —— MySQL 的安装
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档