人生苦短,我用Python~ 界内的Python宣传标语,对Python而言,这是种标榜,实际上,Python确实是当下最好用的开发语言之一。
在相继学习了C++/C#/Java之后,接触Python,最一开始突然一片茫然,似乎是进入了新世界,所有C家族的语法,在这里都或多或少地发生了改变,方法没有大括号,喜闻乐见的格式。定义变量不需要声明,时间长了,竟爱上了这个简介明了,高效快捷的语言,当然,也是当下开发语言界内的宠儿,不可否认,Python是当下最流行的开发语言了。
【前言】
本文拟使用Python开发语言实现在任何能链接上互联网的地方,远程启动在其他地方部署的监控系统,并且实时地进行图像连拍,将实时图像以邮件形式反馈到手机邮箱,达到远程实时监控的目的。
【实现功能】
这篇文章将要介绍的主要内容如下:
1、远程发送监控命令
2、监控系统做出相应,进行图像连拍(或者是录制一段视频)
3、监控系统将处理结果以邮件形式发送到移动端
【实现思路】
远程向某邮箱服务器发送一封邮件,监控系统循环检测此邮箱最新接受的邮件,通过获取并分析邮件的信息确定是否需要执行监控功能操作。如果需要,做出响应,拍照并且将拍照结果反馈回邮件发送方。
【所需技术】
1、Python语言的熟练掌握,Python版本2.7
2、利用Python语言,实现SMTP协议以及POP3协议。已达到发送邮件和接收邮件的功能。
3、正则表达式的简单使用
4、OpenCV 图像处理,图像识别,跨平台开发库的使用
5、邮箱服务器SMTP,POP3协议的开通
【实现过程】
1、实现Python发送接收邮件代码,最后封装成Email_Helper_DG类,便于后续调用,当然本文的Python_Helper_DG还没有达到更高层次的封装,毕竟要发送图片的,适当做了一些对本系统的适应。
邮件发送接受的Email_Helper_DG代码如下:
1 # -*- coding: UTF-8 -*-
2 import os
3 import poplib
4 import smtplib
5 from email.mime.application import MIMEApplication
6 from email.mime.audio import MIMEAudio
7 from email.mime.image import MIMEImage
8 from email.mime.multipart import MIMEMultipart
9 from email.mime.text import MIMEText
10 from email.utils import formataddr
11
12
13 class Mail_Helper_DG:
14 my_smtp_server = 'smtp.sina.com' # smtp 邮件服务地址
15 my_pop3_server = 'pop.sina.com' # pop3 邮件服务地址
16 mail_type = 'html' # 发送的邮件的格式,HTML或者Plain
17 my_account = '******@example.com' # 发件人邮箱账号
18 my_pwd = '******' # 发件人邮箱密码
19 toAddressArray = ['xxxxx@example.com', ] # 收件人的邮箱,可发送给多人
20
21 def __init__(self):
22 pass
23
24 # 发送邮件
25 def SendMail(self, toAddressArray, senderName, subject, content):
26 try:
27 server = smtplib.SMTP(self.my_smtp_server, 25) # 发件人邮箱中的SMTP服务器,端口是25
28
29 try:
30 msg = MIMEText(content, self.mail_type, 'utf-8')
31 msg['From'] = formataddr([senderName, self.my_account]) # 括号里的对应发件人邮箱昵称、发件人邮箱账号
32 # msg['To'] = formataddr(["FK", my_account]) # 括号里的对应收件人邮箱昵称、收件人邮箱账号
33 msg['Subject'] = subject # 邮件的主题,也可以说是标题
34
35 server.login(self.my_account, self.my_pwd) # 括号中对应的是发件人邮箱账号、邮箱密码
36 server.sendmail(self.my_account, toAddressArray, msg.as_string()) # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
37 except Exception:
38 print(Exception)
39 return False
40 finally:
41 server.quit() # 关闭连接
42 return True
43 except Exception:
44 print(Exception)
45 return False
46
47 # 发送邮件带附件
48 def SendMailAttachment(self, toAddressArray, senderName, subject, content, attachment_path):
49 try:
50 server = smtplib.SMTP(self.my_smtp_server, 25) # 发件人邮箱中的SMTP服务器,端口是25
51
52 try:
53 server.login(self.my_account, self.my_pwd) # 括号中对应的是发件人邮箱账号、邮箱密码
54
55 msg = MIMEMultipart() # create MIMEMultipart
56 msg['From'] = formataddr([senderName, self.my_account]) # 括号里的对应发件人邮箱昵称、发件人邮箱账号
57 # msg['To'] = formataddr(["FK", my_account]) # 括号里的对应收件人邮箱昵称、收件人邮箱账号
58 msg['Subject'] = subject # 邮件的主题,也可以说是标题
59 content2 = MIMEText(content,
60 _charset='utf-8') # add email content ,coding is gbk, becasue chinese exist
61 msg.attach(content2)
62 for attachment_name in os.listdir(attachment_path):
63 attachment_file = os.path.join(attachment_path, attachment_name)
64
65 with open(attachment_file, 'rb') as attachment:
66 if 'application' == 'text':
67 attachment = MIMEText(attachment.read(), _subtype='octet-stream', _charset='GB2312')
68 elif 'application' == 'image':
69 attachment = MIMEImage(attachment.read(), _subtype='octet-stream')
70 elif 'application' == 'audio':
71 attachment = MIMEAudio(attachment.read(), _subtype='octet-stream')
72 else:
73 attachment = MIMEApplication(attachment.read(), _subtype='octet-stream')
74
75 attachment.add_header('Content-Disposition', 'attachment', filename=('gbk', '', attachment_name))
76 # make sure "attachment_name is chinese" right
77 msg.attach(attachment)
78
79 server.sendmail(self.my_account, toAddressArray, msg.as_string()) # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
80 except Exception:
81 print(Exception)
82 return False
83 finally:
84 server.quit() # 关闭连接
85 return True
86 except Exception:
87 print(Exception)
88 return
89
90 # 接收邮件
91 def ReceiveMail(self):
92 # 创建一个pop3对象,这个时候实际上已经连接上服务器了
93 pp = poplib.POP3(self.my_pop3_server)
94 # 设置调试模式,可以看到与服务器的交互信息
95 pp.set_debuglevel(1)
96 # 向服务器发送用户名
97 pp.user(self.my_account)
98 # 向服务器发送密码
99 pp.pass_(self.my_pwd)
100 # 返回邮箱的状态,返回2元祖(消息的数量,消息的总字节)
101 # msgCount, msgSize = pp.stat()
102
103 ret = pp.list()
104
105 mailBody = pp.retr(len(ret[1]))
106 # 释放pp
107 pp.quit()
108
109 return mailBody
2、主要业务逻辑代码,其中包含对POP3邮箱的实时监测,且对捕获到的命令进行分析判断,最后做出响应:
1 # -*- coding: UTF-8 -*-
2 import re
3 import time
4 import cv2
5
6 from Email import Mail_Helper_DG
7
8 toAddressArray = ['wd8622088@foxmail.com'] # 收件人的邮箱,可发送给多人
9
10 content = """
11 当前摄像头捕获的结果:
12 """
13
14
15 # 获取当前时间
16 def getCurrentTime():
17 return str(time.strftime('’%Y-%m-%d %X’', time.localtime(time.time())))
18
19
20 # 程序启动标识
21 print('QiXiao`s SHS Starting ...')
22 # 初始化邮件发送类
23 mail = Mail_Helper_DG()
24
25 # 声明一个变量,来作为一个标记判断是否已经检测过当前这封邮件了
26 last_receiveMailDate = ''
27 # 输出显示当前扫描邮箱服务器的次数
28 scan_index = 0
29 # 设置一个循环检测邮箱的方法
30 while True:
31 time.sleep(10) # 设置检测邮箱服务器的时间间隔
32 print(getCurrentTime() + ' : scan item >>> ' + str(scan_index))
33 scan_index += 1 # 扫描次数累加
34 try:
35 # 通过Pop3 获取到邮件的第一条
36 mailBody = mail.ReceiveMail()
37
38 # 解析第一条邮件,并得到发件人,主题,日期
39 sender = re.search("X-Sender: (.*?)'.", str(mailBody[1]).decode(('utf-8')), re.S).group(1)
40 subject = re.search("Subject: (.*?)'.", str(mailBody[1]).decode(('utf-8')), re.S).group(1)
41 date = re.search("Date: (.*?)'.", str(mailBody[1]).decode(('utf-8')), re.S).group(1)
42
43 # 判断解析到的参数值
44 if date != last_receiveMailDate:
45 # 对发送方进行邮箱判断,否则任何人都可以发送命令,你懂得
46 if sender == 'wd8622088@foxmail.com':
47 # 对命令进行分析
48 if subject.__contains__('qx_cmd:'):
49 cmd = subject.split(':')[1]
50 # 按cmd的命令来匹配要执行的操作:
51 # catch-camera 捕获摄像头的操作
52 if cmd == 'catch-camera':
53 # 载入图像,连续捕获数张图片,间隔三秒
54 video = cv2.VideoCapture(0)
55 time.sleep(3)
56 ret, img = video.read()
57 cv2.imwrite('files\\shoot_001.jpg', img)
58
59 time.sleep(3)
60 ret, img = video.read()
61 cv2.imwrite('files\\shoot_002.jpg', img)
62
63 time.sleep(3)
64 ret, img = video.read()
65 cv2.imwrite('files\\shoot_003.jpg', img)
66
67 video.release() # 关闭摄像头
68 result = mail.SendMailAttachment(toAddressArray, "QiXiao",
69 "QiXiao`s SHS (QiXiao`s Smart Home System v1.0)", content,
70 "files")
71 if result is True:
72 print(getCurrentTime() + ' : send mail success !')
73 else:
74 print(getCurrentTime() + ' : send fail #')
75
76 # 让当前这条信息的日期赋值给标记变量,以便下次略过当前这条信息
77 last_receiveMailDate = date
78 except Exception:
79 print(getCurrentTime() + 'Error:' + Exception)
至于代码逻辑的分析,代码内部已有适当的注释进行讲解,这里不再赘述,如有任何疑问,请留言,本人进行一一回复。
【系统测试】
首先我们启动我们的服务器,让代码跑起来。
每隔一段时间,服务器就会自动请求一次POP3服务器,判断是否有新的命令输入。
然后我们在任何地点进行邮件命令的发送:这里以Ios自带的Mail来进行邮件的发送(邮件客户端无所谓,微信里的也可以)
我们首先要填写好要发送的邮箱地址,以及主题(这里是约定好的执行命令)
填写好后,点击发送。
可以看到在0:00发送了一条邮件,这就是我们刚才发送的邮件。然后打开收件箱,准备进行邮件的查收。
我们可以看到,两分钟后,服务端以邮件形式返回监控的结果。打开邮箱进行查看。
我们可以看到,摄像头正对的部位被成功捕获,并且反馈到我们发送邮件的邮箱中。
通过这样的方式,我们可以在全球任意位置,向邮箱发送邮件,只要存在网络的地方,都可以实时对任意位置部署的摄像头进行监控,实时返回监控结果。
我们打开我们的接收命令的邮箱查看一下我们接受到的邮件:
没错,是我们刚才发送的邮件。
我们程序文件目录下保存的截取图片:
至此,我们的远程监控系统已经测试完毕,可见,完美达到了预期的效果!
【系统展望】
系统虽然功能已经实现,然还有很多不尽人意之处,未来将在第二版进行改进的有:
1、系统每隔一定时间间隔自动进行拍照,然后图像分析是否有区别(有物体入侵),如果有立即发送邮件推送报警信息。
2、对图片进行人脸识别,用方框圈出人连范围,以便增加提醒。
3、系统将搭建于Raspberry Pi Linux微机系统上,并且配备摄像头全天候进行跟踪拍摄。
4、未来可能搭建web服务,在网站或者App上进行此功能的使用