点击链接查看上文:https://blog.csdn.net/weixin_43624626/article/details/125818438
本系统所使用的两个开发板为ESP8266-NodeMCU和ESP32-CAM模块,非常方便的一点是,这两个开发板的程序编写以及程序编译烧入都可以使用Arduino IDE软件完成。
通过程序控制,能够实现系统的初始化和MCU对各个检测家庭环境的传感器的数据采集,以及WiFi模块的初始化。采集的数据可以实时的显示在OLED屏幕上,MCU通过分析部分传感器返回的环境参数能够判断当前环境是否存在安全问题,能够起到家庭安防的作用,对安防警报信息能够及时通过声光报警和远程微信预警信息通知给人们。并且用户可以随时随地的通过微信实时查看视频监控。
(1)ESP8266的程序流程图如下图所示
(2)ESP32-CAM模块程序流程图:
DHT11接收到主机(MCU)发送的启动信号后,DHT11立即从低功率模式切换到高速模式。主机启动信号结束后,DHT11发送响应信号,发送40位数据并触发信号采集。信号发送时序图如下图所示
(1)DHT11数据格式。DHT11发送的一次数据由5个字节构成,分为整数部分和小数部分,高位在前(左)。数据的格式如下:
8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+ 8bit校验位。校验位为前四个字节相加结果的末8位。
(2)驱动程序。温度与湿度的获取是在主程序中通过使用dht11库文件获取,库文件包含一个dht11.h文件和一个dht11.cpp文件。在dht11.cpp通过uint8_t bytes[5]语句定义了一个含有5个元素的字节数组,该数组用来存放dht11按照时序传递的数据。根据DHT11的DATA引脚的电平时序变化判断出要准备接收40位bit,在接收数据时只对高电平持续时间进行计时,高电平持续26 ~ 27us表示数据“0”,而高电平持续68 ~ 74us表示数据“1”,“0”和“1”的时序图如图4.5。由于68us~74us为一个时间范围,存在一定的误差,若延时太短,无法判断当前是处于数据“0”的时隙还是数据“1”的时隙;如果延时太长,则会错过下一位数据前的开始时隙,从而后续数据无法被检测,因此在程序中将高电平持续时间大于40us作为对有效高电平进行的判断的依据。
dh11.h 的代码 ↓
#ifndef dht11_h
#define dht11_h
#if defined(ARDUINO) && (ARDUINO >= 100)
#include
#else
#include
#endif
#define DHT11LIB_VERSION "0.4.1"
#define DHTLIB_OK 0
#define DHTLIB_ERROR_CHECKSUM -1
#define DHTLIB_ERROR_TIMEOUT -2
class dht11
{
public:
int read(int pin);
double humidity;
double temperature;
};
#endif
dh11.cpp 的代码 ↓
#include "dht11.h"
// Return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht11::read(int pin)
{
// BUFFER TO RECEIVE
uint8_t bytes[5];//定义一个含有5个元素的字节数组
uint8_t cnt = 7;//二进制1左移的位数
uint8_t idx = 0;//字节数组编号
// EMPTY BUFFER 清空
for (int i=0; i< 5; i++) bytes[i] = 0;
// REQUEST SAMPLE
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delay(18);
digitalWrite(pin, HIGH);
delayMicroseconds(40);
pinMode(pin, INPUT);
// ACKNOWLEDGE or TIMEOUT
unsigned int loopCnt = 10000;
while(digitalRead(pin) == LOW)
if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
loopCnt = 10000;
while(digitalRead(pin) == HIGH)
if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
// READ OUTPUT - 40 bytes => 5 BYTES or TIMEOUT
for (int i=0; i<40; i++){
loopCnt = 10000;
while(digitalRead(pin) == LOW)
if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
unsigned long t = micros();
loopCnt = 10000;
while(digitalRead(pin) == HIGH)
if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
if ((micros() - t) > 40) bytes[idx] |= (1 << cnt);
if (cnt == 0){ // 这时就要接收下一个字节的数据了
cnt = 7; // 重置cnt
idx++; // bytes数组下表++,切换存放数据的bytes数组元素
}
else cnt--; //
}
// WRITE TO RIGHT VARS
// as bytes[1] and bytes[3] are allways zero they are omitted in formulas.
humidity = bytes[0];
temperature = bytes[2]+int(bytes[3])/10.0;
uint8_t sum = bytes[0] + bytes[1] + bytes[2] + bytes[3];
if (bytes[4] != sum&0xFF) return DHTLIB_ERROR_CHECKSUM; // 校验
return DHTLIB_OK;
}
//
// END OF FILE
//
MQ-2烟雾传感器软件设计流程图如下图所示:
ESP8266-NodeMCU开发板对MQ-2烟雾传感器的数据采集方式较为简便,不需要使用驱动程序。烟雾传感器包含数字开关量输出和模拟电压量的输出,在主程序中调用analogRead(A0)函数读取其模拟引脚A0的数值即可。
火焰检测软件设计流程图如下图所示:
ESP8266-NodeMCU通过读取DO引脚的电平高低就可以判断出附近是否有火焰。
判断房门是否被打开的程序流程图如下图所示:
使用软件进行编程,实现超声波测距传感器的测距功能,测得的距离是传感器到房门的距离,对测得的距离的大小进行检测,以此判断门是否被打开了。
根据时序图(如下),超声波测距传感器的触发方式为10微秒以上的高电平脉冲,在程序中实现10微秒以上的高电平脉冲则是使用digitalWrite函数和微秒级延时函数delayMicroseconds,对超声波测距传感器的trig引脚写入12微秒的高电平脉冲,然后使用pulseIn函数检测echo引脚返回的高电平的持续时间,该时间就是从超声波发出到碰到物体返回的时间,该时间乘以声速的结果就是要测距离的2倍。
人体红外检测的程序流程图如下图所示:
ESP8266-NodeMCU连接HC-SR312,在主程序中通过digitalRead函数读取HC-SR312的OUT引脚电平值,读取OUT引脚电平值的程序存放在hongwai函数中。由于HC-SR312有2秒的延时时间,所以每隔2秒对OUT引脚的数据采集一次。
声光报警的子程序流程图如下图所示:
声光报警的实现是使用程序控制蜂鸣器发出响声和点亮LED灯,两个是同时工作的。声光报警的软件设计主要是根据室内烟雾浓度是否超过阈值、是否检测到火焰、有无人员闯入、房门是否被打开这些条件进行判断。
声光报警的程序封装为函数,在需要报警的程序段调用该函数即可完成本地的声光报警。
此设计选用的0.96寸OLED屏是使用SSD1306芯片驱动4线IIC接口来实现屏幕的点亮。OLED的驱动主要是通过使用U8g2库来完成,U8g2是一个用于屏幕显示的单色图形库,兼容大部分的主流的单色OLED和LCD显示屏,在Arduino IDE的库管理器中进行安装。
OLED四线IIC接口与MCU通信的时序图如下图4.12所示
屏幕上的显示内容为MCU获取到的温湿度、烟雾、明火、人体感应、家门开关状态这些环境数据。为了保证整体主程序的模块化,通过自定义的显示函数OLEDDispaly(String temp, String rh, String gas, String fire, String human)来驱动屏幕显示环境数据。
主程序中对OLED屏幕的显示控制主要包括以下的内容。首先通过构造器对进行初始化,包括显示的缓冲区大小、通信协议、屏幕显示方向等。然后确定U8g2绘制模式,为了使环境数据的变换能够及时的在显示屏上显示出来,采用了U8g2库中的Full screen buffer mode(全屏缓存模式),该显示模式有固定的U8g2库函数调用顺序,顺序颠倒或者错误调用都不能正常驱动屏幕进行显示。使用该显示模式的程序控制过程:调用u8g2.clearBuffer清除内存中的数据缓冲区,为了使屏幕显示出相关信息,通过u8g2.setFont设置字符集,类似与编码格式;依据屏幕像素点阵的X轴和Y轴布局,使用u8g2.setCursor设置要绘制内容的起始坐标位置;利用u8g2.print函数指明屏幕上要显示的内容信息,写入缓冲区;最后调用u8g2.sendBuffer将缓冲区中的字符内容显示到屏幕上。
云平台作为环境监测与家庭安防系统数据处理和下放的枢纽,连接着下位机ESP8266与上位机微信小程序终端,整个系统的正常运转和云平台的可靠性与否息息相关。考虑到完全自主设计云服务器的开发难度大、周期长、成本较高,因此选择使用专门的物联网云服务平台—— 巴法云 作为本系统云平台进行开发。
巴法云还提供了微信消息推送的API接口,可以在本系统中得到很好的应用,能够进行安防报警信息的实时推送。
MQTT规范的中文版本说明了MQTT是一种以用户端为基础的发布/订阅方式的信息传送协议。其设计思路是轻巧、开放、简单、规范、易于实施。这些特性使其成为许多情况下的最佳选项,尤其是在诸如机器与机器之间的通讯(M2M)和IoT等有限的环境中。
相对于HTTP等协议, MQTT在网络上的数据传输性能更好。另外,本协议的一个重要特征就是可以很容易地在客户端上实现。MQTT是目前国际上应用最广泛的物联网技术。在汽车网络、智能家居、即时聊天、工业互联网等方面,已经得到了广泛的应用。MQTT协议为设备提供了稳定、可靠和易于使用的通信基础。
数据上传至巴法云程序流程图如下图所示
巴法云中的MQTT设备云作为MQTT服务端,ESP8266-NodeMCU作为MQTT客户端可以向MQTT服务端特定主题发布消息和订阅某一主题。
ESP8266的Arduino开发环境里有多个MQTT库,最为流行的莫属 PubSubClient 库,ESP8266客户端的配置依托于PubSubClient库进行建立。在ESP8266上仅用一个MQTT客户端,使用代码 PubSubClient mqttclient(wifiClient) 初始化一个PubSubClient对象mqttclient。使用setServer函数设置MQTT服务器地址和端口号,用connect函数将客户端与服务端连接。
将ESP8266-NodeMCU采集到的各项传感器数据上传到巴法云MQTT服务端的实现是往所建立的MQTT主题发布消息,发布消息用到PubSubClient库中的publish函数。由于存在多个传感器,每个传感器的数据单独使用一个publish函数发布消息的话会占用太多程序资源,且显得程序过于冗杂,所以将所有要上传的数据放在一条字符串类型消息中进行发布,为了之后便于区分每个数据的所属者,需将数据进行简单的封装,就是将消息的格式设定为 “#data1#data2#data3…”,使用了“#”对各项数据进行“分割”,之后提取数据时对消息字符串按“#”分割后保存在数组中,即可按数组下标提取对应数据。
小程序的首页界面是用来显示家庭中的各项环境参数,有温度、湿度、天然气含量、人体感应、家门开关状态、火焰检测,还显示了当前设备是否在线。
文件结构
index.wxml界面文件是界面布局的程序,该文件中的代码是对界面进行渲染,界面中对应数据的显示是在index.js逻辑文件中进行设置。
微信小程序获取巴法云数据的流程图如下图所示
在小程序获取数据之前需要判断当前设备是否在线,主要是检测MQTT服务端的主题是否有客户端定订阅,调用了巴法云获取设备状态的API接口。通过wx.request函数发起https网络请求,若请求成功,使用success回调函数接收服务端返回的json对象数据,解析json数据,对json对象中的“status”成员的值进行判断,若“status”的值为“online”,表示设备在线,若值为“offline”,则表示设备已离线。
在小程序端配置MQTT客户端,为了能够接收数据需要订阅ESP8266发布消息的对应主题,只要ESP8266一旦发布消息,小程序就能够及时的接收到消息。为了能够在小程序端建立一个MQTT客户端,使用了MQTT.js这个开源库,由于本设计使用的MQTT协议相对简单,实际使用的是对MQTT.js进行裁剪后的库,名为mqtt.min.js库。
调用mqtt.min.js库中的mqtt.connect连接巴法云MQTT服务端,使用subscribe函数订阅ESP8266发布消息的主题,使用on方法进行“message”事件绑定,“message”事件是定义在mqtt.min.js库中的,每当有新消息发布,“message”事件就会被触发,同时会运行message函数获取新发布的消息,这个消息就是所有的传感器的数据,由于消息的格式设定为了“#data1#data2#data3…”,使用split函数对消息字符串按照“#”进行分割即可分别获取对应传感器的数据。
采用本地声光报警虽然能起到对到盗贼等陌生人的警示惊动的作用,但家中没有人还是不能对家庭安全提供切实的保障。采用微信消息形式的远程报警可以说是一种有效的方式。微信消息推送的功能是基于巴法云物联网云平台所提供的微信推送API接口实现的,接收端的配置流程如下:
(1)注册企业微信。 (2)获取企业ID。在“我的企业”选项栏中找到企业生成的企业ID,将该企业ID保存并填入到巴法云微信推送的配置界面中。
(3)在企业微信中新建一个应用。打开“应用管理”,在最下面找到“创建应用”,点击创建应用。
(4)对要创建的应用设置名称和logo。
(5)创建完成后,进入创建的应用详情页,可以获取到应用ID(agentid),应用密钥Secret(secret),将密钥保存下来。
(6)打开巴法云的微信消息推送的配置界面,将前面获得的企业ID、应用ID、应用密钥Secret填入到对应的位置,完成巴法云端的配置。
要想使用户的微信能够接收到企业微信通知,可以直接用微信扫码关注微信插件,这样成员无需下载企业微信客户端就可在微信中接收企业通知和使用企业应用。用户通过微信扫码关注“家庭安防消息推送”这个插件后表示用户已经进入了“家庭安防消息推送”这个“企业’,还不能接收在企业中所开放的应用的消息,还需管理员进行人员的添加,添加人员如下图所示
ESP8266作为为客户端,通过请求和响应的方式完成微信消息的推送。
微信消息推送实现流程如下图所示:
前面硬件部分也提到了,该部分所用到的硬件开发载体是ESP32-CAM,代码编写以及程序的烧写也都是使用的Arduino IDE软件完成的。软件实现过程如下图:
该部分用的程序是用的Github上的一个开源项目中的代码,该项目实现的是使用ESP32-CAM模块实现的多客户端MJPEG流式网络服务器。
该开源项目网址:https://github.com/arkhipenko/esp32-cam-mjpeg-multiclient
它使用FreeRTOS工具来制作一个多客户端流式服务器,即一个用于保存当前流式客户端的队列,用于在流式传输时为新连接请求提供服务的任务,以及用于协调抓取新帧和流式传输现有帧的信号量,它可以处理多达10个连接的客户端。
源码包含5个文件,一个主程序,三个头文件和一个C++文件。
对必要的参数进行修改。进入到home_wifi_multi.h文件中,此文件是存放WiFi名称以及WiFi密码的,修改为自己的WiFi名称和密码。
将ESP32-CAM模块通过USB串口连接电脑进行程序的烧写上传,程序烧写方式和前面的ESP8266一样。烧写上传成功后打开串口监视器,可以看到在监视器中显示出了视频流的IP地址。通过该IP地址就可以访问到ESP32-CAM产生的MJPG视频流。
接下来,在局域网中获取ESP32-CAM产生的MJPG视频流。让电脑也连接ESP32-CAM连接的WiFi,使得电脑和ESP32-CAM在同一个局域网当中,打开浏览器(我这选用的Google浏览器),在网址输入栏中输入上面获取到的ESP32-CAM在当前局域网中产生的视频流IP地址,然后进行访问该IP,可以看到ESP32-CAM上的摄像头所拍摄到的实时画面。
所使用的内网穿透平台:Sunny-Ngrok (https://www.ngrok.cc/)
内网穿透获将内网视频流地址映射到外网的步骤如下图
选择的隧道协议为http,在最下面的本地端口栏填入ESP32-CAM在Arduino IDE串口监视器输出的视频流IP,根据下载的源码中的服务端口设置,IP地址后面要填写端口号为80端口。
打开隧道管理,可以看到自己的隧道id,要将该隧道id保存并记录下来,在后面进行内网穿透时需要用到。
然后再在隧道管理中下载Ngrok客户端:
在下图中可以看到可以看到隧道的状态为online,表示在线。其中还给出了一项Forwarding,这一项后面的IP地址就是将内网视频流的IP所映射到的哪个公网IP,通过该公网IP可以访问到视频流信息。
在另一台电脑中打开浏览器,同时该电脑不和ESP32-CAM在同一个局域网,在浏览器中访问这个内网穿透后的公网IP地址http://sunqktest.free.idcfengye.com,当然访问视频流的话要访问http://sunqktest.free.idcfengye.com/mjpeg/1。
可以看到,内网穿透成功,在浏览器中能够显示ESP32-CAM摄像头所捕捉的实时画面,如图xx所示。
由于视频流的格式是MJPEG(M-JPEG或MJPEG,Motion Joint Photographic Experts Group,FourCC:MJPG)格式,这是一种影像压缩格式,其中的每一帧图像都分别使用了JPEG编码,MJPEG格式通常用在数字相机和摄像头之类的图像采集设备上。
ESP32-CAM模块所产生的视频流的格式为MJPEG,该种格式的视频由于每一帧的图像都是使用JPEG编码,所以在微信小程序小程序中使用image图片组件来显示所接收到的视频流资源,因此添加image组件并设置好视频资源地址,添加的关键代码如下图所示:
将代码保存运行之后在开发工具左边的模拟器中的显示如下图所示,可以接收到视频流资源并且能够显示出来。微信端的家庭远程监控就此实现!
⭐项目的代码:https://download.csdn.net/download/weixin_43624626/86242778