人生苦短,我用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上进行此功能的使用