查看: 331|回复: 7

[项目] 【智控万物】微信QQ邮件温度计

[复制链接]
本帖最后由 云天 于 2021-1-26 20:51 编辑

Screenshot_20210125_221511_com.tencent.mm.jpg


【项目设计】

可通过微信直接看到家里的室温,不用打开微信小程序或其它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/

MonJanuary-202101257881..png

QQ截图20210125224735.png QQ截图20210125224924.png

开启POP3/SMTP服务

因要向QQ邮箱发送邮件,所以要设置自己的QQ邮箱开启POP3/SMTP服务,同时通过手机发送验证短信,生成授权码。
TueJanuary-202101269172..png

Forgotten补充设置过程图片


MonJanuary-202101259278..png

【微信开启QQ邮箱提醒】

MonJanuary-202101256458..png



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

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

连接示意图
LM35_Diagram.png


IMG_20210125_230635.jpg


【代码编写】


#!/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([Form_name,Form])  # 括号里的对应发件人邮箱昵称、发件人邮箱账号
        msg['To']=formataddr([To_name,To])              # 括号里的对应收件人邮箱昵称、收件人邮箱账号
        msg['Subject']=Content                # 邮件的主题,也可以说是标题

        server=smtplib.SMTP_SSL("smtp.qq.com", 465)  # 发件人邮箱中的SMTP服务器,端口是25
        server.login(Form, Password)  # 括号中对应的是发件人邮箱账号、邮箱密码
        server.sendmail(Form,[To,],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([Form_name,Form])  # 括号里的对应发件人邮箱昵称、发件人邮箱账号
        msg['To']=formataddr([To_name,To])              # 括号里的对应收件人邮箱昵称、收件人邮箱账号
        msg['Subject']=Content                # 邮件的主题,也可以说是标题

        server=smtplib.SMTP_SSL("smtp.qq.com", 465)  # 发件人邮箱中的SMTP服务器,端口是25
        server.login(Form, Password)  # 括号中对应的是发件人邮箱账号、邮箱密码
        server.sendmail(Form,[To,],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)
TueJanuary-202101268026..png









汤果  初级技神

发表于 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
TueJanuary-202101266913..png
回复

使用道具 举报

云天  中级技匠
 楼主|

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

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

已增加,感谢!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2021 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail