云天 发表于 2021-1-25 23:14:08

【智控万物】微信QQ邮件温度计

本帖最后由 云天 于 2021-1-26 20:51 编辑



【项目设计】
可通过微信直接看到家里的室温,不用打开微信小程序或其它APP。使用Mind+中 Python 模式“PinPong库”。
【PinPong库】
PinPong库是一套控制开源硬件主控板的Pyhton库,基于Firmata协议并兼容MicroPython语法,5分钟即可让你上手使用Python控制开源硬件。借助于PinPong库,直接用Python代码就能给各种常见的开源硬件编程。其原理是给开源硬件烧录一个特定的固件,使开源硬件可以通过串口与电脑通讯,执行各种命令。PinPong库的名称由“Pin”和“Pong”组成,“Pin”指引脚,“PinPong”为“乒乓球”的谐音,指信号的往复。pinpong库的设计,是为了让开发者在开发过程中不用被繁杂的硬件型号束缚,而将重点转移到软件的实现。哪怕程序编写初期用Arduino开发,部署时改成了掌控板,只要修改一下硬件的参数就能正常运行,实现了“一次编写处处运行”。
【Mind+ Python模式】
http://mindplus.cc/
【开启POP3/SMTP服务】

因要向QQ邮箱发送邮件,所以要设置自己的QQ邮箱开启POP3/SMTP服务,同时通过手机发送验证短信,生成授权码。
Forgotten补充设置过程图片


【微信开启QQ邮箱提醒】



https://kf.qq.com/touch/faq/1506 ... Uz.html?platform=14

【硬件】
主控板使用Arduino uno,温度传感器为:LM35线性模拟温度传感器

连接示意图




【代码编写】


#!/usr/bin/python
# -*- coding: UTF-8 -*-

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
import time
from pinpong.board import Board,Pin,ADC
Board("uno").begin()
adc0 = Pin(Pin.A0, Pin.ANALOG)
my_sender='********@qq.com'    # 发件人邮箱账号
my_pass = 'syzwyzj***xuqbgbi'   # 发件人邮箱密码(授权码)
my_user='*******@qq.com'      # 收件人邮箱账号,我这边发送给自己



def mail(Form,Form_name,Password,To,To_name,Title,Content):
    ret=True
    try:
      msg=MIMEText(Title,'plain','utf-8')
      msg['From']=formataddr()# 括号里的对应发件人邮箱昵称、发件人邮箱账号
      msg['To']=formataddr()            # 括号里的对应收件人邮箱昵称、收件人邮箱账号
      msg['Subject']=Content                # 邮件的主题,也可以说是标题

      server=smtplib.SMTP_SSL("smtp.qq.com", 465)# 发件人邮箱中的SMTP服务器,端口是25
      server.login(Form, Password)# 括号中对应的是发件人邮箱账号、邮箱密码
      server.sendmail(Form,,msg.as_string())# 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
      server.quit()# 关闭连接
    except Exception:# 如果 try 中的语句没有执行,则会执行下面的 ret=False
      ret=False
    return ret
while True:
    v = adc0.read_analog()
    tem = round(v*(5/10.24),1)
    print(tem)
    ret=mail(my_sender,"QQ邮件温度计",my_pass,my_user,"温度","当前室内温度为",str(tem)+"℃")
    if ret:
      print("邮件发送成功")
    else:
      print("邮件发送失败")
    time.sleep(60)


【邮件协议】

发送邮件——SMTP协议

SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP协议属于TCP/IP协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。通过SMTP协议所指定的服务器,就可以把E-mail寄到收信人的服务器上了,只要几分钟。

接收邮件——POP3和IMAP

POP是指邮局协议,目的是让用户可以访问邮箱服务器中的邮件,允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时删除保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的。
后来又出现了IMAP协议(Interactive Mail Access Protocol),即交互式邮件访问协议,与POP3的不同在于:开启了IMAP后,在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。

【发送邮件,获取室内温度】
以下代码实现,每60秒测试一次邮箱中是否有主题为“温度”的邮件。如果有,发送当前温度到邮箱。


#!/usr/bin/python
# -*- coding: UTF-8 -*-
import poplib
import datetime
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
import time
from pinpong.board import Board,Pin,ADC
Board("uno").begin()
adc0 = Pin(Pin.A0, Pin.ANALOG)
my_sender='********@qq.com'    # 发件人邮箱账号
my_pass = 'syzwy*****qbgbi'            # 发件人邮箱密码(授权码)
my_user='*********@qq.com'      # 收件人邮箱账号,我这边发送给自己

# 此函数通过使用poplib实现接收邮件
def recv_email_by_pop3(QQ_Address,Password):
    # 要进行邮件接收的邮箱。改成自己的邮箱
    email_address = QQ_Address
    # 要进行邮件接收的邮箱的密码。改成自己的邮箱的密码
    # 设置 -> 账户 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 -> 开启服务:POP3/SMTP服务
    # 设置 -> 账户 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 -> 生成授权码
    email_password = Password
    # 邮箱对应的pop服务器,也可以直接是IP地址
    # 改成自己邮箱的pop服务器;qq邮箱不需要修改此值
    pop_server_host = "pop.qq.com"
    # 邮箱对应的pop服务器的监听端口。改成自己邮箱的pop服务器的端口;qq邮箱不需要修改此值
    pop_server_port = 995

    try:
      # 连接pop服务器。如果没有使用SSL,将POP3_SSL()改成POP3()即可其他都不需要做改动
      email_server = poplib.POP3_SSL(host=pop_server_host, port=pop_server_port, timeout=10)
      print("pop3----connect server success, now will check username")
    except:
      print("pop3----sorry the given email server address connect time out")
      exit(1)
    try:
      # 验证邮箱是否存在
      email_server.user(email_address)
      print("pop3----username exist, now will check password")
    except:
      print("pop3----sorry the given email address seem do not exist")
      exit(1)
    try:
      # 验证邮箱密码是否正确
      email_server.pass_(email_password)
      print("pop3----password correct,now will list email")
    except:
      print("pop3----sorry the given username seem do not correct")
      exit(1)

    # 邮箱中其收到的邮件的数量
    email_count = len(email_server.list()[1])

    # list()返回所有邮件的编号:
    resp, mails, octets = email_server.list()
    # 遍历所有的邮件
    if len(mails)>0 :
    #for i in range(1, len(mails) + 1):#这里只读最新收到的邮件
      # 通过retr(index)读取第index封邮件的内容;这里读取最后一封,也即最新收到的那一封邮件
      resp, lines, octets = email_server.retr(len(mails))
      # lines是邮件内容,列表形式使用join拼成一个byte变量
      email_content = b'\r\n'.join(lines)
      try:
            # 再将邮件内容由byte转成str类型
            email_content = email_content.decode('utf-8')
      except Exception as e:
            print(str(e))

      # # 将str类型转换成<class 'email.message.Message'>
      # msg = email.message_from_string(email_content)
      msg = Parser().parsestr(email_content)
      return(parse_email(msg, 0))


    # 关闭连接
    email_server.close()
def parse_email(msg, indent):
    if indent == 0:
      # 邮件的From, To, Subject存在于根对象上:
      for header in ['From', 'To', 'Subject']:
            value = msg.get(header, '')
            if value:
                if header=='Subject':
                  # 需要解码Subject字符串:
                  value = decode_str(value)
                  print(value)
                  return value
                else:
                  # 需要解码Email地址:
                  hdr, addr = parseaddr(value)
                  name = decode_str(hdr)
                  value = u'%s <%s>' % (name, addr)
            #print('%s%s: %s' % ('' * indent, header, value))

# 解码
def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
      value = value.decode(charset)
    return value

# 猜测字符编码
def guess_charset(msg):
    # 先从msg对象获取编码:
    charset = msg.get_charset()
    if charset is None:
      # 如果获取不到,再从Content-Type字段获取:
      content_type = msg.get('Content-Type', '').lower()
      for item in content_type.split(';'):
            item = item.strip()
            if item.startswith('charset'):
                charset = item.split('=')[1]
                break
    return charset
def mail(Form,Form_name,Password,To,To_name,Title,Content):
    ret=True
    try:
      msg=MIMEText(Title,'plain','utf-8')
      msg['From']=formataddr()# 括号里的对应发件人邮箱昵称、发件人邮箱账号
      msg['To']=formataddr()            # 括号里的对应收件人邮箱昵称、收件人邮箱账号
      msg['Subject']=Content                # 邮件的主题,也可以说是标题

      server=smtplib.SMTP_SSL("smtp.qq.com", 465)# 发件人邮箱中的SMTP服务器,端口是25
      server.login(Form, Password)# 括号中对应的是发件人邮箱账号、邮箱密码
      server.sendmail(Form,,msg.as_string())# 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
      server.quit()# 关闭连接
    except Exception:# 如果 try 中的语句没有执行,则会执行下面的 ret=False
      ret=False
    return ret
while True:
    if recv_email_by_pop3(my_sender,my_pass)=="温度":
      v = adc0.read_analog()
      tem = round(v*(5/10.24),1)
      print(tem)
      ret=mail(my_sender,"QQ邮件温度计",my_pass,my_user,"温度","当前室内温度为",str(tem)+"℃")
      if ret:
         print("邮件发送成功")
      else:
         print("邮件发送失败")
    time.sleep(60)










汤果 发表于 2021-1-26 06:45:45

这个很不错诶!

hnyzcj 发表于 2021-1-26 07:24:50

邮件服务

rzyzzxw 发表于 2021-1-26 18:13:01

赞啦

Forgotten 发表于 2021-1-26 18:24:24

有用,收藏了

Nick-ccq 发表于 2021-1-26 18:26:49

强,学习一波

Forgotten 发表于 2021-1-26 19:51:36

本帖最后由 Forgotten 于 2021-1-26 19:56 编辑

测试成功,非常方便,感谢楼主补充一下,在设置>账户中开启POP

云天 发表于 2021-1-26 20:51:50

Forgotten 发表于 2021-1-26 19:51
测试成功,非常方便,感谢楼主补充一下,在设置>账户中开启POP

已增加,感谢!
页: [1]
查看完整版本: 【智控万物】微信QQ邮件温度计