用 esp8266 当感知到人体活动时,在中断函数中记录一个标志变量,然后 loop 循环判断标志变量是否为 true,如果是则发送邮件通知。
源代码
邮件发送代码做了部分优化
//To use send Email for qq to port 465 (SSL)
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
// PIR OUTPUT端口 D6 GPIO12 LED端口 D4 GPIO2
const int LED = 2;
const int PIR_sensor = 12;
// 获取当前时间
unsigned long now = millis();
// 上一次触发中断的时间
unsigned long lastTrigger = 0;
boolean humanTrigger = false;
/* wifi ssid和密码 */
#define WIFI_SSID "xxxx"
#define WIFI_PASSWORD "xxxxxx"
/* qq 邮箱的 smtp 地址和端口号 */
#define SMTP_HOST "smtp.qq.com"
#define SMTP_PORT 465
/*
你的邮箱和授权码 授权码是QQ邮箱推出的,用于登录第三方客户端的专用密码。
如何获取授权码 https://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256
*/
#define AUTHOR_EMAIL "xxxxx@qq.com"
#define AUTHOR_PASSWORD "xxxxxx"
/* 接收人邮箱地址 email*/
#define RECIPIENT_EMAIL "xxxxxxx@qq.com"
/* 定义 smtp session 对象*/
SMTPSession smtp;
ESP_Mail_Session session;
/* 获取邮件发送状态的回调函数 */
void getSmtpStatusCallback(SMTP_Status status);
// 检测人体感应的中断触发函数,将LED置为高电平
ICACHE_RAM_ATTR void detectHuman() {
Serial.println("Human Detected!!!");
digitalWrite(LED, HIGH);
humanTrigger = true;
}
void irSetup(){
// 将人体感应数据口连接的IO口设置为输入上拉模式,使引脚即使在未连接外部组件的时候也能保持确定的逻辑电平。
pinMode(PIR_sensor, INPUT_PULLUP);
// 将人体感应数据口连接的IO口设置为中断模式, 赋值中断函数和将中断模式设置为RISING(当引脚由低电平变为高电平时,触发中断)
attachInterrupt(digitalPinToInterrupt(PIR_sensor), detectHuman, RISING);
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
}
void wifiSetup(){
Serial.println();
Serial.print("连接 Wifi");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED){
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi 连接成功.");
Serial.println("IP 地址: ");
Serial.println(WiFi.localIP());
Serial.println();
}
void smtpSetup(){
/* smtp开启debug,debug信息输出到串口 */
smtp.debug(0);
/* 注册回调函数,获取邮件发送状态 */
smtp.callback(getSmtpStatusCallback);
/* 设置smtp 相关参数, host, port等 */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "";
/* 连接smtp服务器 */
if (!smtp.connect(&session))
return;
}
/* 获取发送状态的回调函数 */
void getSmtpStatusCallback(SMTP_Status status){
/* 输出邮件发送状态信息 */
Serial.println(status.info());
/*状态获取成功,打印状态信息 */
if (status.success()){
Serial.println("----------------");
ESP_MAIL_PRINTF("邮件发送成功个数: %d\n", status.completedCount());
ESP_MAIL_PRINTF("邮件发送失败个数: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++){
/* 依次获取发送邮件状态 */
SMTP_Result result = smtp.sendingResult.getItem(i);
time_t ts = (time_t)result.timestamp;
localtime_r(&ts, &dt);
ESP_MAIL_PRINTF("收件人: %s邮件发送状态信息\n", result.recipients);
ESP_MAIL_PRINTF("状态: %s\n", result.completed ? "success" : "failed");
ESP_MAIL_PRINTF("发送时间: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
ESP_MAIL_PRINTF("邮件标题: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}
void emailSendHtml(char* subject, char* recipient, String htmlMsg){
/* 定义smtp message消息类 */
SMTP_Message message;
/* 定义邮件消息类的名称,发件人,标题和添加收件人 */
message.sender.name = "Esp8266er";
message.sender.email = AUTHOR_EMAIL;
message.subject = subject;
message.addRecipient("Sara", recipient);
message.html.content = htmlMsg.c_str();
message.html.content = htmlMsg.c_str();
message.text.charSet = "us-ascii";
message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
/* 调用发送邮件函数,失败的话,获取失败信息 */
if (!MailClient.sendMail(&smtp, &message))
Serial.println("发送邮件失败,失败原因是 , " + smtp.errorReason());
}
void setup(){
Serial.begin(115200);
wifiSetup();
irSetup();
smtpSetup();
}
void loop(){
if (humanTrigger) {
String htmlMsg = "<div style=\"color:#2f4468;\"><h1>Human Detected!!!</h1><p>Send from Esp8266er</p></div>";
emailSendHtml("Esp8266er Email", RECIPIENT_EMAIL, htmlMsg);
humanTrigger = false;
}
}
邮件示例
image
如果将发送邮件放到中断函数里面,板子会不断重启,邮件发送不出去,初步猜测应该是发送邮件有一定的时间,放在中断函数阻塞时间太长了,导致触发了芯片的软件狗重置。
欢迎关注我的公众号“玩转 esp8266”,原创技术文章第一时间推送。