20元制作NodeMCU+超声波模块+Python开门检测神器
目录
前言
最近出来实习,一个人住出租屋每天晚上回来总感觉屋子里面有人来过,因此像制作一个开门预警通知的小工具。
效果图
原理也很简单:单片机检测与门的距离,距离小于设定值且持续一段时间(2s),发邮件给我预警。
硬软件条件
- 1.NodeMCU+超声波
- 2.云端服务器(不用也可以,本地部署也可以的,但是必须NodeMCU与部署的电脑同局域网,知道内网穿透的同学当我没说)
- 3.Arduino IDE
- 4.Python+flask发邮件
单片机程序
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#ifndef STASSID
#define STASSID "WiFi_SSID"
#define STAPSK "WiFi_PASSWD"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
const char* host = "your.sendMail.host";
const int httpsPort = 5000;
// Use web browser to view and copy
// SHA1 fingerprint of the certificate
const char fingerprint[] PROGMEM = "5F F1 60 31 09 04 3E F2 90 D2 B0 8A 50 38 04 E8 37 9F BC 76";
// 定义引脚编号
const int trigPin = 2; //D4
const int echoPin = 0; //D3
// 定义变量
long duration;
int distance;
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT); // 将trigPin设置为输出
pinMode(echoPin, INPUT); // 将echoPin设置为输入
Serial.println();
Serial.print("connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void alarm(String info){
// Use WiFiClientSecure class to create TLS connection
WiFiClient client;
Serial.print("connecting to ");
Serial.println(host);
// http 访问此链接,发送邮件
String url = "/send_email?info="+info;
Serial.print("requesting URL: ");
Serial.println(url);
// Serial.printf("Using fingerprint '%s'\n", fingerprint);
// client.setFingerprint(fingerprint);
if (!client.connect(host, httpsPort)) {
Serial.println("connection failed");
return;
}
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");
Serial.println("request sent");
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
Serial.println("headers received");
break;
}
}
String line = client.readStringUntil('\n');
if (line.startsWith("{\"state\":\"success\"")) {
Serial.println("esp8266/Arduino CI successfull!");
} else {
Serial.println("esp8266/Arduino CI has failed");
}
Serial.println("reply was:");
Serial.println("==========");
Serial.println(line);
Serial.println("==========");
Serial.println("closing connection");
}
float getDistance(){
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
//将trigPin设置为HIGH状态10微秒
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// 读取echoPin,以微秒为单位返回声波传播时间
duration = pulseIn(echoPin, HIGH);
// 计算距离
distance= duration*0.034/2;
// 打印距离在串行监视器
Serial.print("Distance: ");
Serial.println(distance);
return distance;
}
int num=0;
int sum_num=0;
void loop() {
while(true){
int d = getDistance();
delay(200);
if(d<50){
num++;
if(num>10){
alarm(String(d));
num=0;
}
}
if(sum_num>100){
sum_num=0;
num=0;
}
}
}
服务器端代码
# -*- coding: utf-8 -*-
from flask import Flask, request
from flask_script import Manager, Shell
from flask_mail import Mail, Message
from threading import Thread
import os
app = Flask(__name__)
app.config['MAIL_SERVER'] = 'smtp.qq.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = 'xxx@qq.com'
app.config['MAIL_PASSWORD'] = 'pwd'
mail = Mail(app)
msg = Message('⚠️警告⚠️', sender='xxx@qq.com', recipients=['xxxx@foxmail.com'])
msg.body = '内容'
# with app.app_context():
# mail.send(msg)
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
@app.route('/send_email')
def send_email():
msg.html = '<h1>Door is opened</h1><p>Maybe somebody open the door, please confirm!</p>'
thread = Thread(target=send_async_email, args=[app, msg])
thread.start()
return 'success'
if __name__ == '__main__':
app.run(host="0.0.0.0",port=5000)