esp32-cam 赤外線リアルタイム監視および警報システム
ヴィジョン・バ・ファユン
人体アラームを検出する人体赤外線センサーを作成し、同時に携帯電話にアラームリマインダーを送信し、同時に写真のデザインを送信したいと考えています。いくつかの情報を見つけたところ、Bafayun esp32-cam と人体赤外線センサーを組み合わせて、私の要件を満たすことができます。よくできました。コードは以下のように表示されます。
/*
* 2020-07-07
* QQ交流群:824273231
* 微信:19092550573
* 官网https://bemfa.com
*
*此版本需要json库,再arduino IDE 选项栏,点击“工具”-->"管理库"-->搜索arduinojson 第一个库就是,点击安装即可
*
分辨率默认配置:config.frame_size = FRAMESIZE_UXGA;
其他配置:
FRAMESIZE_UXGA (1600 x 1200)
FRAMESIZE_QVGA (320 x 240)
FRAMESIZE_CIF (352 x 288)
FRAMESIZE_VGA (640 x 480)
FRAMESIZE_SVGA (800 x 600)
FRAMESIZE_XGA (1024 x 768)
FRAMESIZE_SXGA (1280 x 1024)
config.jpeg_quality = 10;(10-63)越小照片质量最好
数字越小表示质量越高,但是,如果图像质量的数字过低,尤其是在高分辨率时,可能会导致ESP32-CAM崩溃
*支持发布订阅模式,当图片上传时,订阅端会自动获取图片url地址,可做图片识别,人脸识别,图像分析
*/
#include <HTTPClient.h>
#include "esp_camera.h"
#include <WiFi.h>
#include <ArduinoJson.h>
/*********************需要修改的地方**********************/
const char* ssid = "l"; //WIFI名称
const char* password = "5"; //WIFI密码
int capture_interval = 20*1000; // 默认20秒上传一次,可更改(本项目是自动上传,如需条件触发上传,在需要上传的时候,调用take_send_photo()即可)
const char* post_url = "http://images.bemfa.com/upload/v1/upimages.php"; // 默认上传地址
const char* uid = ""; //用户私钥,巴法云控制台获取
const char* topic = "yi"; //图云主题名字,可在控制台新建
bool sentWechat = true; //是否推送到微信,默认不推送,true 为推送。需要在控制台先绑定微信,不然推送不到
const char* wechatMsg = "有人进入."; //推送到微信的消息,可随意修改,修改为自己需要发送的消息
/********************************************************/
bool internet_connected = false;
long current_millis;
long last_capture_millis = 0;
// CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
void setup()
{
Serial.begin(115200);
//PIR初始状态
pinMode(12,INPUT);
digitalWrite(12,LOW);
if (init_wifi()) {
// Connected to WiFi
internet_connected = true;
Serial.println("Internet connected");
}
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
//init with high specs to pre-allocate larger buffers
if (psramFound()) {
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
}
/********初始化WIFI*********/
bool init_wifi()
{
int connAttempts = 0;
Serial.println("\r\nConnecting to: " + String(ssid));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED ) {
delay(500);
Serial.print(".");
if (connAttempts > 10) return false;
connAttempts++;
}
return true;
}
/********推送图片*********/
static esp_err_t take_send_photo()
{
//初始化相机并拍照
Serial.println("Taking picture...");
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
return ESP_FAIL;
}
HTTPClient http;
//设置请求url
http.begin(post_url);
//设置请求头部信息
http.addHeader("Content-Type", "image/jpg");
http.addHeader("Authorization", uid);
http.addHeader("Authtopic", topic);
if(sentWechat){
//判断是否需要推送到微信
http.addHeader("Wechatmsg", wechatMsg); //设置 http 请求头部信息
}
//发起请求,并获取状态码
int httpResponseCode = http.POST((uint8_t *)fb->buf, fb->len);
if(httpResponseCode==200){
//获取post请求后的服务器响应信息,json格式
String response = http.getString(); //Get the response to the request
Serial.print("Response Msg:");
Serial.println(response); // 打印服务器返回的信息
//json数据解析
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, response);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
}
const char* url = doc["url"];
Serial.print("Get URL:");
Serial.println(url);//打印获取的URL
}else{
//错误请求
Serial.print("Error on sending POST: ");
Serial.println(httpResponseCode);
}
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
//清空数据
esp_camera_fb_return(fb);
//回收下次再用
http.end();
}
void loop()
{
//PIR检测电平变化
if(digitalRead(12)==HIGH)||(digitalRead(13)==HIGH) {
Serial.println("Somebody is here.");
take_send_photo();
}
else {
Serial.println("Nobody.");
}
delay(1000);
}
ツイスト - 写真制限
しかし、問題もあります。ライブラリの料金が高すぎるためかもしれません。Bafayun には無料で 100 枚の写真を保存できます。それを超える場合は、メンバーシップを開く必要があります。さらに、これらの 100 枚の写真は永久的であり、1 回限りです最近経済が逼迫しており、すでに山の上に座っているので、以下のような優れたクラウドプラットフォームをサポートしたいと思っていますが、恥ずかしがっています。いろいろ調べても解決策が見つからなかったので、写真の転送を他の方法に変えていたところ、メールの添付ファイルで自分のメールボックスに送信できるという記事を見たので、そうすることにしました。これは、人体赤外線センサーを WeChat にアップロードして、esp8266 を使用して Bafa Cloud にアラームを送信するためのコードです。アラームの数に制限はありませんが、テキスト リマインダーのみです。画像無し。
コード
/*
* 微信通知提醒
* 2021-3-26
* QQ 1217882800
* https://bemfa.com
*
* 注意:由于微信更新的原因,此版本可能失效,可在 https://cloud.bemfa.com/tcp/wechat.html 页面查看新接口教程
*/
//esp8266头文件,需要先安装esp8266开发环境
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
/******************************************************************************/
#define DEFAULT_STASSID "newhtc" //WIFI名称
#define DEFAULT_STAPSW "qq123456" //WIFI密码
String uid = "4d9ec352e0376f2110a0c601a2857225"; // 用户私钥,巴法云控制台获取
String type = "2"; // 1表示是预警消息,2表示设备提醒消息
String device = "人体红外传感器设备"; // 设备名称
String msg = "检测到"; //发送的消息
int delaytime = 0; //为了防止被设备“骚扰”,可设置贤者时间,单位是秒,如果设置了该值,在该时间内不会发消息到微信,设置为0立即推送。
String ApiUrl = "http://api.bemfa.com/api/wechat/v1/"; //默认 api 网址
/******************************************************************************/
static uint32_t lastWiFiCheckTick = 0;//wifi 重连计时
WiFiClient client; //初始化wifi客户端
HTTPClient http; //初始化http
//=======================================================================
// WIFI重新连接函数
//=======================================================================
void startSTA(){
WiFi.disconnect();//断开连接
WiFi.mode(WIFI_STA);//设置wifi模式
WiFi.begin(DEFAULT_STASSID, DEFAULT_STAPSW);// 开始连接
}
//=======================================================================
// WIFI状态检测函数,如果WIFI断开自动重连
//=======================================================================
void doWiFiTick(){
if ( WiFi.status() != WL_CONNECTED ) {
//如果没连接
if (millis() - lastWiFiCheckTick > 1000) {
//未连接1s重连,检查是否大于1秒
lastWiFiCheckTick = millis();
startSTA();//重新连接
}
}
}
//=======================================================================
// 初始化
//=======================================================================
void setup() {
delay(1000);
Serial.begin(115200); //设置串口波特率
WiFi.mode(WIFI_OFF); //设置wifi模式
delay(1000);
WiFi.mode(WIFI_STA); //设置wifi模式
WiFi.begin(DEFAULT_STASSID, DEFAULT_STAPSW); //开始连接wifi
Serial.println("");
Serial.print("Connecting");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
//检查是否连接成功
delay(500);
Serial.print(".");
}
//如果连接成功,打印ip等信息
Serial.println("");
Serial.print("Connected to ");
Serial.println(DEFAULT_STASSID);
Serial.print("IP address: ");
Serial.println(WiFi.localIP()); //IP 地址
}
//=======================================================================
// 主循环
//=======================================================================
void loop() {
doHttpStick();//在想推送消息的地方执行推送函数即可
delay(20000);//20s推送一次,可删除delay,在想推送消息的地方执行推送函数即可
}
//******微信消息推送函数********//
void doHttpStick(){
//微信消息推送函数
String postData;
//Post Data
postData = "uid="+uid+"&type=" + type +"&time="+delaytime+"&device="+device+"&msg="+msg;
http.begin(client,ApiUrl); //Specify request destination
http.addHeader("Content-Type", "application/x-www-form-urlencoded"); //Specify content-type header
int httpCode = http.POST(postData); //Send the request
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
http.end(); //Close connection
Serial.println("send success");
}
//=======================================================================
バファユンの写真制限を回避する
私のアイデアは、これを esp32-cam ボードに移植することです。<ESP8266WiFi.h> ヘッダー ファイルを <6WiFi.h> に変更する必要がありますが、doHttpStick() WeChat メッセージ プッシュ機能を esp32-cam ボードに配置すると、 、実行できないことがわかり、<ESP8266HTTPClient.h> のヘッダー ファイルが <HTTPClient.h> に変更され、http 未定義エラーが表示され、http.begin(client,ApiUrl); が行われていないことがわかりました。 http を前に定義していないので、コード文の後に HTTPClient http; を追加しました、ついに動作しました。次のコードは正常にコンパイルされます。
#include <HTTPClient.h>
#include "esp_camera.h"
#include <Arduino.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include "ESP32_MailClient.h"
/*********************需要修改的地方**********************/
const char* ssid = "l"; //WIFI名称
const char* password = ""; //WIFI密码
/********************************************************/
/******************************************************************************/
String uid = "e5f"; // 用户私钥,巴法云控制台获取
String type = "1"; // 1表示是预警消息,2表示设备提醒消息
String device = "传感器设备"; // 设备名称
String msg = "有人进入"; //发送的消息
int delaytime = 0; //为了防止被设备“骚扰”,可设置贤者时间,单位是秒,如果设置了该值,在该时间内不会发消息到微信,设置为0立即推送。
String ApiUrl = "http://api.bemfa.com/api/wechat/v1/"; //默认 api 网址
/******************************************************************************/
bool internet_connected = false;
long current_millis;
long last_capture_millis = 0;
// CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
SMTPData smtpData;
//void sendCallback(SendStatus info);
void setup()
{
Serial.begin(115200);
if (init_wifi()) {
// Connected to WiFi
internet_connected = true;
Serial.println("Internet connected");
}
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
//init with high specs to pre-allocate larger buffers
if (psramFound()) {
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
}
/********初始化WIFI*********/
bool init_wifi()
{
int connAttempts = 0;
Serial.println("\r\nConnecting to: " + String(ssid));
WiFi.begin(ssid, password);
WiFi.setAutoReconnect(true);
while (WiFi.status() != WL_CONNECTED ) {
delay(500);
Serial.print(".");
if (connAttempts > 10) return false;
connAttempts++;
}
return true;
}
static esp_err_t sendMail2m() {
//初始化相机并拍照
Serial.println("Taking picture...");
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
return ESP_FAIL;
}
Serial.println("Sending email...");
smtpData.setLogin("smtp.qq.com", 465, "@qq.com", "授权码");
smtpData.setSender("ESP32", "");
smtpData.setPriority("High");
smtpData.setSubject("有人!!");
smtpData.setMessage("有人闯入!", true);
smtpData.addRecipient(".com");
smtpData.addAttachData("firebase_logo.jpg", "image/jpg", (uint8_t *)fb->buf, fb->len);
//从内存中
smtpData.setSendCallback(sendCallback);
if (!MailClient.sendMail(smtpData)){
Serial.println("Error sending Email, " + MailClient.smtpErrorReason());
esp_restart() ;
}
smtpData.empty();
//清空数据
esp_camera_fb_return(fb);
}
void loop()
{
//定时发送
//当前时间减去上次时间大于20S就执行拍照上传函数
//PIR检测电平变化
if((digitalRead(12)==HIGH)||(digitalRead(13)==HIGH)) {
Serial.println("有人进入.");
sendMail2m(); //拍照上传函数,在需要的地方调用即可,这里是定时拍照
doHttpStick();//在想推送消息的地方执行推送函数即可
}
else {
Serial.println("Nobody.");
}
delay(1000);
}
void sendCallback(SendStatus msg)
{
Serial.println(msg.info());
if (msg.success())
{
Serial.println("----------------");
}
}
//******微信消息推送函数********//
void doHttpStick(){
//微信消息推送函数
HTTPClient http;
String postData;
//Post Data
postData = "uid="+uid+"&type=" + type +"&time="+delaytime+"&device="+device+"&msg="+msg;
http.begin(ApiUrl); //Specify request destination
http.addHeader("Content-Type", "application/x-www-form-urlencoded"); //Specify content-type header
int httpCode = http.POST(postData); //Send the request
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
http.end(); //Close connection
Serial.println("send success");
}
メールボックスピット
でも、最初はqqメールボックスを使っていましたが、qqメールボックスの設定方法と設定がわかり、認証コードは取得できましたが、シリアルポートツール経由では認証が拒否されると出続けたので考え方を変更しました163 個のメールボックスに変更して、ようやく気づきました。