前言
本项目作为毕业设计项目,题目是《基于物联网技术的机房环境监测系统》,其中分为终端部分和服务器部分,终端部分主要进行温湿度采集、烟雾情况采集、水浸情况采集、人体闯入情况采集的数据采集功能、摄像头监控、数据上传功能,另外在网页进行数据的接收、存储、展示的工作。
在项目开始初期采用的方案是树莓派+OneNet云平台的方式进行的,这样会节省很大的开发时间,而且比较简单。在后续时间充足的情况下,进行了个人的云端服务器的搭建工作,包括网站后台程序的编写和mysql数据库的设计。网址:www.xddd.top
终端部分
终端部分由各个传感器、树莓派摄像头、树莓派开发板组成,主要进行数据的采集、处理、上传工作。
树莓派
设备选择中采用树莓派4B开发板,主要进行数据的处理和上传工作。系统采用官方推荐的Raspbian,这是一款基于Debian Linux的树莓派专用系统。具体安装方式请参考https://zhuanlan.zhihu.com/p/59027897。
共有两种连接树莓派的方法,对于熟悉Linux命令的同学可以使用Putty软件,输入正确的树莓派ip地址后进行ssh连接方式。另一种可以使用远程桌面的方式,在图形化界面中使用树莓派。
1.安装Putty
具体安装方法参考https://shumeipai.nxez.com/2013/09/07/using-putty-to-log-in-to-the-raspberry-pie.html。可以使用一根网线将树莓派与路由器相连接,在路由器的管理界面可以看到树莓派的ip地址。或者将树莓派与电脑直接连接,通过cmd的arp -a命令查看树莓派的ip地址,这部分有参考https://blog.csdn.net/makunIT/article/details/107312982。
在连接成功后可以将树莓派通过wifi联网,或者还可以在树莓派SD卡中提前写好wifi地址,免去连线的烦恼。
2.远程桌面
使用widwos自带的远程桌面连接服务,只需要直接填入ip地址。
使用VNC服务,参考https://www.jianshu.com/p/7f0422a816a3。
硬件设备
传感器部分主要进行数据的采集工作,其中有:温湿度传感器:DHT11;烟雾传感器:ZYMQ-2 气体传感器;水浸传感器:WLS-06-1000 电极式水浸传感器;人体红外传感器:用 HC-SR501 人体传感器。另外选用一个三色指示灯和一个有源蜂鸣器做报警模块、一个一路继电器和一个小风扇做风扇控制模块。
因为采用设备较多,而树莓派上的VCC和GND引脚不够,所以采用一个面包板提供电流和接地,其中各模块VCC接5V,GND接地,DO接树莓派的GPIO引脚。其中有源蜂鸣器的VCC引脚需要接到树莓派3.3V,接到5V会一直响。其他各模块接到GPIO引脚,具体连接方式见下表。
传感器 | 引脚 | BCM |
---|---|---|
烟雾传感器 | 7 | 4 |
水浸传感器 | 12 | 18 |
温湿度传感器 | 11 | 17 |
人体红外传感器 | 37 | 26 |
一路继电器 | 13 | 27 |
有源蜂鸣器 | 32 | 12 |
LED红 | 40 | 21 |
LED黄 | 38 | 20 |
LED绿 | 36 | 16 |
其中树莓派GPIO引脚采用BCM规则,关于BCM规则和GPIO的控制方式部分见参考链接https://blog.csdn.net/qq_36958104/article/details/83447224?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=1328603.26400.16150139156282599&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
软件编写
编程语言采用Python3,具体安装方式见链接https://blog.csdn.net/weixin_43371047/article/details/103763373。
1.温湿度监测
温湿度监测部分使用了Adafruit_Python_DHT库的函数,具体安装方式参考链接https://zhuanlan.zhihu.com/p/74440206。另外代码部分参考链接为https://blog.csdn.net/qq_27320195/article/details/107766284?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242。
sample1.py
# encoding:utf-8
import Adafruit_DHT
import time
DHT_SENSOR = Adafruit_DHT.DHT11
DHT_PIN = 17
def start():
while True:
humidity, temperature = Adafruit_DHT.read(DHT_SENSOR, DHT_PIN)
if humidity is not None and temperature is not None:
print("温度={0:0.1f}C 湿度={1:0.1f}%".format(temperature, humidity))
else:
print("传感器读取失败.")
time.sleep(3)
if __name__ == "__main__":
try:
start()
except KeyboardInterrupt:
exit()
2.烟雾情况监测
烟雾未检测到则向树莓派输出高电平,检测到烟雾则输出低电平。具体高低电平方式看选用传感器的触发方式,针对不同的触发方式,更改条件即可。后续水浸、人体红外和烟雾代码类似,只需要更改引脚和触发方式即可。此部分有参考https://blog.csdn.net/zhq_blog/article/details/88671175。
smoke.py
#!/usr/bin/python
# encoding:utf-8
import RPi.GPIO as GPIO
import time
pin_fire = 4
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin_fire, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
try:
while True:
status = GPIO.input(pin_fire)
if status == True:
print('没有检测到烟雾')
else:
print('检测到有烟雾')
time.sleep(0.5)
except KeyboradInterrupt:
GPIO.cleanup()
3.数据上传
数据上传方式选择HTTP协议的post方法,采用JSON数据格式。
获取当前时间的方法参考https://www.jb51.net/article/91365.htm。
ali_test.py
import urllib.request
import requests
import json
from time import strftime
from datetime import datetime
#阿里云上传数据
'''
温度 = temp_value
湿度 = hum_value
烟雾 = yanwu_value
水浸 = shuijin_value
红外 = hongwai_value
'''
url = 'http://www.xddd.top:80/dataPort'
def data_put():
now_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
data={
'time_value':now_time,'temp_value':66.6,'hum_value':66.6,'smoke_value':0,'water_value':0,'human_value':0}
requests.post(url,data)
data_put()
4.邮箱报警
邮箱部分代码参考https://blog.csdn.net/weixin_41789943/article/details/82348946。
email.py
import smtplib
from email.mime.text import MIMEText
from email.header import Header
mail_host="smtp.163.com"
mail_user="*******.com"
mail_pass="*******"
sender = '******@163.com'
receivers = ['******@qq.com','******@163.com']
body_content = """ 测试文本 """
message = MIMEText(body_content, 'plain', 'utf-8')
message['From'] = "********@163.com"
message['To'] = "******@qq.com"
subject = """
项目异常测试邮件
"""
message['Subject'] = Header(subject, 'utf-8')
smtpObj = smtplib.SMTP()
smtpObj.connect(mail_host, 25)
smtpObj.set_debuglevel(1)
smtpObj.login(mail_user,mail_pass)
smtpObj.sendmail(sender, receivers, message.as_string())
print("邮件发送成功")
smtpObj.quit()
————————————————
版权声明:本文为CSDN博主「无面骑士」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41789943/article/details/82348946
5.短信报警
短信报警方面使用的是腾讯云的短信业务,因为腾讯提供免费的200条短信服务。
代码部分有腾讯的云API中API Explorer自动生成。腾讯云API链接为https://console.cloud.tencent.com/api/explorer。
具体参数部分见其附带的参考文档,填写好需要发送的手机号,签名,模板就可进行短信的发送业务了。
tx_test.py
#腾讯的API,短信发送模块
import json
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sms.v20190711 import sms_client, models
#烟雾报警短信
def duanxin_yanwu():
try:
cred = credential.Credential("AKID0nhKwJVgPs5lGXhAAqFP8QW4ImzyNpAF", "a0vby3VqrfJYYSZVEk3xc07nEd9sKXr0")
httpProfile = HttpProfile()
httpProfile.endpoint = "sms.tencentcloudapi.com"
clientProfile = ClientProfile()
clientProfile.httpProfile = httpProfile
client = sms_client.SmsClient(cred, "", clientProfile)
req = models.SendSmsRequest()
params = {
"PhoneNumberSet": [ "+86**********" ],
#TemplateID:模板ID
"TemplateID": "*****",
"Sign":"*****",
"SmsSdkAppid":"******"
}
req.from_json_string(json.dumps(params))
resp = client.SendSms(req)
print(resp.to_json_string())
except TencentCloudSDKException as err:
print(err)
阿里云服务器
服务器采用了阿里云服务器,只购买了三个月,买了一个一年的域名,总共花了不到60块钱。采用LNMP 7.4镜像,系统为Ubuntu 18,数据库为MySQL。
后台程序
后台程序选择使用nodejs中的express框架进行编写。express框架的学习参考https://www.jianshu.com/p/06e2396c6df2,
B站视频有,nodejs+express学习:https://www.bilibili.com/video/BV11t411k79h、NodeJS+express+MySQL实现博客系统:https://www.bilibili.com/video/BV1Rz4y1m7pt。
登录和注册部分参考https://blog.csdn.net/qq_38209578/article/details/82666820?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162117821716780264033511%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162117821716780264033511&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-1-82666820.first_rank_v2_pc_rank_v29&utm_term=mysql%E5%92%8Cnodejs%E7%BD%91%E9%A1%B5%E7%99%BB%E5%BD%95%E9%A1%B5%E9%9D%A2。
表格显示部分参考https://blog.csdn.net/blue__k/article/details/109081947?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.control。
文件目录结构为
其中login_test.js作为运行的主程序,主要进行对数据的解析,存储和展示工作。
页面的直接显示采用 ajax方法,参考了https://www.jb51.net/article/57874.htm。其中涉及到跨域的问题,也参考了https://blog.csdn.net/weixin_45000814/article/details/106841193?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161884057416780265451177%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=161884057416780265451177&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-106841193.pc_search_result_no_baidu_js&utm_term=CORS+nodejs。
login_test.js
//Setup basic express server
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var bodyParser = require('body-parser');
const http = require('http');
const path = require('path');
const fs = require('fs');
const mysql = require("mysql");
const common = require('./module/common.js');
app.use(express.static(path.join(__dirname + '/static/css')));
app.use(express.static(path.join(__dirname + '/static/js')));
app.use(express.static(path.join(__dirname + '/static/images')));
app.use(express.static(path.join(__dirname + '/static/font')));
app.use(express.static(path.join(__dirname + '/static')));
//设置模板引擎
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
var UserSQL = {
insert: 'INSERT INTO login(username,password) VALUES(?,?)', //插入数据
drop: 'DROP TABLE user',
queryALL: 'SELECT * FROM user',
getUserById: 'SELECT * FROM user WHERE username=?',//查找符合条件的数据
};
module.exports = UserSQL;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false}));
//存放数据库机房环境信息
var arr = [];
app.listen(80,()=>{
console.log("网页运行端口在80端口...");
})
const db = mysql.createConnection({
host:"localhost",
user:"****",
password:"******",
database:"pchome"
})
db.connect((err)=>{
if(err) throw err;
console.log('连接成功');
})
app.get("/",(req,res)=>{
let pathname = req.url;
pathname=pathname=='/'?'/login.html':pathname;
//获取后缀名
let extname =path.extname(pathname);
//2、通过fs模块读取文件
fs.readFile('./static' + pathname,(err, data