基于arduino与raspberry的远程数据采集系统
该课题是毕业时做的一个远程数据采集课题,今天无意翻看到这份报告,不禁勾起满满的怀念。重新看了一遍报告,感觉做的确实是挺low的,但想起当时自己查了无数的资料,才完成这个设计,尤其是人在学校,然后通过浏览器直接远程查看到了自己家里面的环境状况,那种喜悦与自豪,对于一个理科生来说,是完全没法用语言来描述的。不过,在构思与设计期间也确实踩了很多坑,故在此分享记录一下,更希望能有有缘的学弟与学妹能够在该设计基础上做一个改进。
系统结构:传感器节点采用arduino搭载DHT11采集温度与湿度参数,嵌入式系统采用raspberryPi3,raspberryPi3用于接收传感器节点数据,同时搭载HTTP服务用于局域网远程访问,最后通过反向端口转发技术,实现真正公网远程访问,系统结构如下:
硬件部分的设计与实现分为构建传感器节点和搭建数据节点,传感器节点和数据节点通信三个部分。构建传感器节点,包括使用传感器进行数据采集和数据传输,课题中将通过DTH11温湿度传感器结合Arduino控制器采集温度和湿度,通过串口通信的方式,实现数据传输与显示;数据节点搭建,目的是为传感器节点发送过来的数据选择一个合适的保存位置与保存方式,其核心便是要实现数据的存储和读取便利性,由于课题中的采集数据量不是很大,只采集温度和湿度两个环境参数,同时为了传感器节点与数据节点之间通信的方便,课题中的数据节点设计中将以文件的格式来实现数据的存储于读取,而文件主要是依靠操作系统来创建与管理,故实现数据节点核心便是为嵌入式设备Raspberry移植一个操作系统,使Raspberry搭载操作系统同时也将为课题后面实现数据远程访问做准备;传感器节点与数据之间的通信设计课题中系统通信设计的核心,只有保证传感器节点采集到的数据能够并且准确地上传到数据节点中,才能为后面远程监测提供数据基础,提供准确的数据是通信的基本要求,传感器节点与数据节点之间的通信,课题中选择SPI转无线模块NRF24L01来实现他们之间的数据传输。下面便依次介绍三个部分的具体的实现过程。
2.1传感器节点的构建
传感器节点是由传感器和用于传输与控制的控制器组成。本课题中拟采集的参数有两类,分别为温度和湿度,为简化采集过程与通信过程,课题中采用集成的温湿度传感器为DHT11,控制器为开源的Arduino控制器。传感器DHT11将采集到的数据发送到控制器,用于下一步传感器节点与数节点之前无线数据传输。
DHT11数字温湿度传感器是自带校准数字信号输出的传感器,内部封装了一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相接。在检测温湿度时,该传感器会自动调用OTP内存中的校准系数,使检测结果更加准确。,其测量温湿度范围与精度如表2-1所示:
表2-1 DHT11温湿度参数表
|
量程 |
精度 |
温度 |
0-50℃ |
±2℃ |
湿度 |
20-90%RH |
±5%RH |
由于其内部也集成了一个8位单片机并且为用户了通信引脚,其引脚说明如表2-2所示,故可以非常方便的将其测量到的数据发送到其他MCU设备用于显示或者存储,其典型的通信应用电路连接如下图2.1所示。
表2-2 DHT11引脚说明
PIN |
名称 |
注释 |
1 |
VDD |
供电3-5.5V DC |
2 |
DATA |
单总线串行数据线 |
3 |
GND |
电源负极接地 |
课题中选择的MCU为开源的Arduino UNO控制器,故DHT11,将通过图2.1中的DATA单总线串行接口以一定的通信协议将其测量得到的温度与湿度的值发送到MCU,即Arduino控制器,具体通信过程如下图所示。
图2.1典型应用电路
DATA引脚用于MCU与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间为4ms左右,数据分为小数和整数两部分,具体数据格式如:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和,总共是40位数据,其中校验和为“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”,用于判断传输过程中数据是否出现错误。
DHT11的数据采集与通信的完整过程如图2.2所示,当MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,完成这个握手过程后,DHT11送出40bit的数据,并触发一次信号采集, 用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集,采集数据后又转换到低速模式。
图2.2 DHT11通信过程
DHT11与MCU的握手通信过程如图2.3所示,总线空闲状态为高电平,当准备开始通信时,主机吧总线拉低必须要大于18ms,保证DHT11能够检测到起始信号,等待主机开始信号结束后,延时等待20-40us,从机然后发送80us低电平的响应信号,再然后将总线拉高,切换为输入模式,开始接受传输数据。
图2.3主从机握手协议方式
数字0与1的表示方式分别如图2.4和2.5所示,总线从高电平拉为低电平,保持50us,然后总线又将从低电平拉为高电平,,高时间为26-28us则表示数字0,拉高时间为70us则表示为数字1,因此在主机读取40位数据时,便可以通过判断总线被拉高的时间长短来判断,接收的数据是0还是1,完整的数据读取过程见2.1.4小节。
图2.4数字0表示方式
图2.5数字1表示方式
Arduino是一个开源的单片机微控制器,采用了Atmel AVR单片机,构建于开放源代码 simple I/O 接口板,并且具有使用类似 Java,C 语言的 Processing/Wiring 开发环境。 由于它的软硬件是开源的,各大厂商可以在遵循GPL许可证的基础上根据自己的需求在进行多样的自定义设计,因此市场上出现了很多系列的arduino单片机,比如Arduino Uno、Arduino Nano、Arduino Nano、Arduino Mega 2560、Arduino Leonardo等系列,有时即使是同一系列的单片机,采用的核心控制芯片型号也会不一样,故在本课题中选择Uno系列控制器的时候也关注了它的主控芯片型号。课题中选择的单片机的实物图如图2.6所示,从实物图上可以看到主要通信接口有usb接口,A0-A5模拟通道I/O口,0-13数字通道I/O口,ISCP接口。
图2.6 Arduino Uno 实物图
课题中选择的Uno系列的主控芯片为ATmage328p, Arduino Uno的端口与ATmage328p引脚接线原理图如图2.7所示。从原理图中可以Uno系列使用了集成UBS转串口芯片CH340,在烧录程序的时候可以非常方便的通过PC上的UBS接口直接给主控芯片写入程序。
图2.7 Arduino Uno原理图
Arduino集成开发工具IDE如图2.8所示,图中图表的主要含义为:
Verify(校验):在下载代码之前对编译好的代码进行校验;
Upload(上传):将编译好的代码下载到Arduino控制板中;
New(新建):可以新建一个程序文件;
Open(打开):可以打开一个已经存在的程序文件;
Save(保存):可以保存当前的程序文件;
图2.8 Arduino IDE
Arduino语言的基础为C语言,但是不同于C语言的是他把AVR单片机底层的一些相关参数设置都函数化,进行二次开发时,我们不需要去了解他的底层设计,只需要通过他已经定义好的函数传入相关的参数便可以达到控制他的所有I/O口效果。关于Arduino语言的基础介绍如下:
1)常量:
LOW/HIGH:表示数字接口的电平高低。LOW表示低电平,HIGH表示高电平;
OUTPUT/INPUT:表示数字I/O口的方向,OUTPUT表示输出,INPUT表示高组态的输入;
true/flase:true表示真1,flase表示假0;
2)程序结构:
void setup():放在程序运行开始位置,可以初始化变量,定义I/O引脚模式,调用库函数等功能;
void loop():放在setup之后,loop中为程序的主体部分,可以让程序循环执行;
3)数字I/O :
pinMode(pin,mode):可以定义数字IO端口的输入输出模式函数,pin的值为0-13,分别对应0-13 IO端口,mode的值有INPUT、OUTPUT分别对应输入和输出模式;
digitalWrite(pin,value):可以定义数字IO端口的输出电平的函数,pin的值为0-13,分别对应0-13 IO端口,value的值有HIGH、LOW分别对应输出高电平1和输出低电平0;
digitalRead(pin,value):可以定义数字IO端口的输入电平的函数,pin的值为0-13,分别对应0-13 IO端口,value的值有HIGH、LOW分别对应输入高电平1和输入低电平0;
4)模拟I/O:
int analogRead(pin): 可以定义模拟IO端口的读函数,pin的值为0-5,分别对应0-5 IO端口;
analogWrite(pin,value)-PWM:数字IO口PWM输出函数,pin的取值为3、5、6、9、10、11,value的取值为0-255,取值越大,输出的PWM的占空比越大。
采用2.1.1节中介绍的典型传感器电路设计数据采集电路,将DHT11上的DATA口连接到Arduino的数字IO口4上,具体Arduino控制器与DHT11温湿度传感器连接接线方式如下表2-3所示:
表2-3 Arduino与DHT11接线方式表
编号 |
Arduino UNO |
DHT11 |
1 |
GND |
GND |
2 |
VCC(5v) |
VCC |
3 |
4 |
DATA |
Arduino和DHT11通信过程可以分为通信握手阶段和温度湿度数据传输阶段。根据2.1.1节中描述的DHT11通信协议,数据采集与通信程序流程图如图2.8和2.9所示,图2.8为DHT11测温采集主流程图,首先是通信握手阶段,整个过程根据图2.3中规定的通信协议进行设计,唯一不同的是对从机是否超时响应进行了一个判断,即图中的使用软件延时,以30000初值递减,但超出这个时间后,将不再等待从机应答,判定为超时,主机将重新发送请求。完整程序设计源代码见附录一
图2.9为对采集到的数据进行0或1判断的子流程图。同时为了方便调试,故测到的数据将通过串口在显示屏上显示,设计思路为:首先记录读取到的低电平时间,然后使用每个数据的总时间减去低电平时间,假如这个值大于50us则此次读到的数据位1,否则读到的数据则为0,并将得到的二进制数据保存到数组中,然后对得到的二进制数据进行转化为十进制,最后使用串口将数据输出显示,以便于直观理解,完整的程序设计源代码见附录一,其中关键程序设计如下:
for(int i=0;i<40;i++) //读取40位数据存入数据chr[]
{
while(digitalRead(pin) == LOW)
{}
time = micros();
while(digitalRead(pin) == HIGH)
{}
if (micros() - time >50)
{
chr[i]=1;
}else{
chr[i]=0;
}
}
//将二进制温度值和湿度值转换为十进制
humi=chr[0]*128+chr[1]*64+chr[2]*32+chr[3]*16+chr[4]*8+chr[5]*4+chr[6]*2+chr[7];
temp=chr[16]*128+chr[17]*64+chr[18]*32+chr[19]*16+chr[20]*8+chr[21]*4+chr[22]*2+chr[23];
//对温度和湿度值进行和校验,并通过串口输出正确的温度值和湿度值
tol=chr[32]*128+chr[33]*64+chr[34]*32+chr[35]*16+chr[36]*8+chr[37]*4+chr[38]*2+chr[39];
if(tol=humi+tol){
Serial.print("temp:");
Serial.println(temp);
Serial.print("humi:");
Serial.println(humi);
}
下图2.10为通过串口进行调试的子流程图,核心代码如下,先通过校验码判断了温度和湿度的准确性,然后使用Arduino的内置封装的串口输出函数Serial.printLn(),输出当前温度和湿度。
if(tol=humi+tol){ //理论上,湿度+温度=校对码 ,如果数值不相等,说明读取的数据有错。
Serial.println(temp);
Serial.println(humi);
}
搭建数据节点的前提是有一个合理的数据存储方式,通常实现数据节点的存储方式有两种,分别为文件存储方式和数据库存储方式。这两种存储方式都是需要底层操作系统系统的支持。因此,用于担任数据节点的硬件系统首先要能够装载操作系统。其次,由于传感器节点和数据节点之间的通信,在正常的使用情况下,是需要数据节点不间断工作的,因此能耗问题不得不考虑,因为搭载了操作系统的主机长时间工作能耗一般都很高。设计中选择的Raspberry Pi,他是一种典型的嵌入系统,而嵌入式系统的能耗相对较低,因此,既可以搭载底层操作系统也可以满足低能耗的要求。使用嵌入式系统作为数据节点,可以有效降低能耗,但它的存储空间非常受限,并且由于课题中采集的数据量不是特别的庞大,,故设计中选择相对较节约内存的文件存储方式。
Linux是一种自由开放源代码的类UNIX操作系统,其内核部分由创始人林纳斯·托瓦兹在1991年10月5日首次发布,再加上用户空间的应用程序,便是我们常说的Linux操作系统。根据市场的不同需求,很多组织、团体、个人会开发用户空间需要用到的特定软件进行打包并制作成镜像文件,方便用户在安装Linux系统后不再需要重复安装一些特定软件,对于这种不同组织发布的镜像文件称其为Linux发行版,课题中使用的Linux操作系统为Raspberry官方制作的Linux发行版,这是一个特地为Raspberry Pi设备设计的操作系统。该系统继承了Debian发行版的特点,因此Debian 系统中的使用的Linux命令基本可以在Raspberry中使用,但不同于Debian的是,该系统在ARMv6和ARMv7 系列中都非常完美地支持了浮点单元,可以满足有大量数学计算的场景,比如传感器数据采集,图像处理等。
在Raspberry Pi上移植操作系统的主要工具有Windows10系统的PC一台、32G TF卡一个、TF卡读卡器一个、Win32Diskimage镜像写入工具 、raspberry官网系统镜像。使用Win32Diskimage镜像写入工具将raspberry镜像写入TF卡,主要过程如图2.11所示。
图2.11 烧录raspberry系统
移植操作系统来后,由于操作系统中自带文件管理系统EXT4,并且Raspberry系统继承于发行版Debian,因此Debian中常用的 linux命令同样适用于Raspberry,因此可以使用常用的linux文件管理命令方便的管理文件,即课题中的数据节点。
嵌入式设备Raspberry Pi,在连接上合适的外设,他既可以作为通用计算机使用,由于具有GPIO口,故也可以作为普通微控制器使用,课题中将充分发挥这个优点,既利用他的通用计算机特点,也利用他的微控制器特点。在2.2.2中将给他搭载操作系统,使他作为通用计算机使用,以便达到使用文件作为中间数据节点的目的,在2.3中将详细介绍利用GPIO口,充分发挥他的微控制特性,实现传感器节点和数据节点进行通信。
课题中使用的Raspberry Pi硬件规格如下:Broadcomd BCM2837的SoC、ARM Crotex-A53 64位(ARMv8系列)1.2GHz(四核心)CPU、1080p高清解码器、1024MB内存、4个USB接口、音源输入/输出、板载MicroSD卡、40个引脚、1个10/100Mbps以太网接口、802.11n无线网络、蓝牙等。他的GPIO的引脚分布如下表2-4所示,其中GPIO7—GPIO11的SPI通信引脚将是课题中将要使用到的数据通信引脚。
表2-4 Raspberry Pi引脚分布
GPIO |
2nd func |
pin |
pin |
2nd func |
GPIO |
N/A |
+3V3 |
1 |
2 |
+5V |
N/A |
GPIO2 |
SDA1(I2C) |
3 |
4 |
+5V |
N/A |
GPIO3 |
SCL1(I2C) |
5 |
6 |
GND |
N/A |
GPIO4 |
GCLK |
7 |
8 |
TXD0(UART) |
GPIO14 |
N/A |
GND |
9 |
10 |
RXD0(UART) |
GPIO15 |
GPIO17 |
GEN0 |
11 |
12 |
GEN1 |
GPIO18 |
GPIO27 |
GEN2 |
13 |
14 |
GND |
N/A |
GPIO22 |
GEN3 |
15 |
16 |
GEN4 |
GPIO23 |
N/A |
+3V3 |
17 |
18 |
GEN5 |
GPIO24 |
GPIO10 |
MOSI(SPI) |
19 |
20 |
GND |
N/A |
GPIO9 |
MISO(SPI) |
21 |
22 |
GEN6 |
GPIO25 |
GPIO11 |
SCLK(SPI) |
23 |
24 |
CE0_N(SPI) |
GPIO8 |
N/A |
GND |
25 |
26 |
CE1_N(SPI) |
GPIO7 |
EEPROM |
ID_SD |
27 |
28 |
ID_SC |
EEPROM |
GPIO5 |
N/A |
29 |
30 |
GND |
N/A |
GPIO6 |
N/A |
31 |
32 |
-- |
GPIO12 |
GPIO13 |
N/A |
33 |
34 |
GND |
N/A |
GPIO19 |
N/A |
35 |
36 |
N/A |
GPIO16 |
GPIO26 |
N/A |
37 |
38 |
Digital_IN |
GPIO20 |
N/A |
GND |
39 |
40 |
Digital_OUT |
GPIO21 |
通信方式按照是否需要物理连接线可以分为有线通信和无线通信,其中有线通信方式主要有串口通信和以太网通信,但考虑到Arduino和嵌入式硬件系统Raspberry之间通信的便携性,有线通信的方式并不是最佳选择,故课题中将会采用无线通信的方式。常用的无线通信方式有wifi、zigbee、蓝牙、射频等,他们之间的主要区别是工作的ISM频段不同。考虑到成本与远程通信的有效距离的要求,课题中选择射频通信的方式,使用的通信模块为SPI转无线模块NRF24L01。
SPI是串行外设接口(Serial Peripheral Interface)的缩写。他是 Motorola 公司推出的一种同步串行接口技术,一种高速的,全双工,同步的通信总线。SPI的通信以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,双向传输时至少需要SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选)4根线,其中每根线的含义如下:
(1)SDO/MOSI – 主设备数据输出,从设备数据输入;
(2)SDI/MISO – 主设备数据输入,从设备数据输出;
(3)SCLK – 时钟信号,由主设备产生;
(4)CS/SS – 从设备使能信号,由主设备控制。
SPI转无线射频模块NRF24L01是Nordic公司研发的一款2.4-2.5GHZ世界通用ISM频段的通信芯片,拥有完整的一套通信协议。主要功能有自动应答与自动重发、内置CRC检错、点对多点通信、2Mbps无线通信速率、0-8Mbps的SPI接口速率,125个可选频道等。通过SPI接口可以进行功率、频道、协议等进行灵活的自定义设置。由于Arduino和raspberry Pi上也都集成了SPI通信接口,因此可以方便地使用该模块实现传感器节点Arduino和数据节点Raspberry Pi进行无线通信。nRF24L01实物图如图2.12所示,其中标注的引脚含义如下表2-5所示:
图2.12 NRF24L01实物图
表 2-5 NRF24L01 引脚分布
引脚1 GND |
NRF24L01 接地引脚 |
引脚2 VCC |
NRF24L01 供电引脚,额定电压为3.3V |
引脚3 CE |
NRF24L01读写控制引脚 |
引脚4 CSN |
NRF24L01片选引脚 |
引脚5 SCK |
NRF24L01时钟引脚 |
引脚6 MOSI |
NRF24L01 SPI主出从入引脚 |
引脚7 MISO |
NRF24L01 SPI主入从出引脚 |
引脚8 IRQ |
NRF24L01 外部中断引脚 |
2.3.2 NRF24L01与Arduino和Raspberry Pi通信
NRF24L01与Arduino通信和NRF24L01与Raspberry Pi通信,分别将他们按照SPI通信方式进行硬件连接,具体引脚连接方式如下表2-6:
表2-6 NRF24L01与Arduino和raspberry Pi通信引脚连接
编号 |
NRF24L01 |
Arduino UNO |
Raspberry Pi |
1 |
GND |
GND |
9(GND) |
2 |
VCC |
3.3V |
1(3.3V) |
3 |
CE |
7(自定义) |
15(GPIO22) |
4 |
CSN |
8(自定义) |
24(GPIO8) |
5 |
SCK |
13 |
23(GPIO11) |
6 |
MOSI |
11 |
19(GPIO10) |
7 |
MISO |
12 |
21(GPIO9) |
8 |
IRQ |
|
|
Raspberry 操作系统对很多外设接口的底层驱动支持,通常都是以模块的方式编译进内核,很多模块默认情况下没有加载运行,在需要时,可以通过手工指定的方式来加载运行。比如SPI底层驱动模块,故需要手动加载底层驱动模块spi_bcm2835。加载方式如下:
1)在终端输入sudo raspi-config,会打开Raspberry Pi的配置界面;
2)依次选择Interfacing Options—SPI –Enable。
3)在终端输入lsmod查看内核已经加载的模块。假如已经加载,设备驱动节点便会出现:/dev 目录下便会多出spidev0.0和spidev0.1两个节点,表示已经成功启动SPI驱动。
使用NRF24L01作为Arduino和Raspberry Pi的中间通信模块,故Arduino和Raspberry Pi两端的程序设计需要相互对应,Arduino端使用NRF24L01按照一定的格式发送数据,那么Raspberry Pi端就应该按照相应的格式解析数据。为了简单NRF24L01的通信过程,课题中将使用NRF24L01官方提供的C++库函数,可以在不需要了解NRF24L01的底层寄存器的配置情况下,直接调用一些数据发送与数据接收等函数, NRF24L01库中的常用类与方法如下,使用这些方法便可以很容易的操作NRF24L01实现数据传输。
bool RF24::begin(void):打开RF24L01的SPI通信,要放在数据传输最开始的位置;
void RF24::setPALevel(uint8_t level):设置电源放大等级,等级分为RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX四种,等级越高,无线传输的距离越远;
void RF24::openWritingPipe(const uint8_t *address):打开管道通信写功能
void RF24::openReadingPipe(uint8_t child, const uint8_t *address)
:打开管道通信读功能
void RF24::startListening(void):打开无线监听
bool RF24::write( const void* buf, uint8_t len ):打开写功能函数
Arduino端程序程序设计流程图如图2.13所示,Arduino使用NRF24L01进行数据发送的主要过程为打开SPI通信,设置电源放大倍数,指定写管道,通过管道将数据写入缓冲区。打开SPI通信,包括SPI驱动初始化使Arduino能够通过GPIO口设别SPI设别、指定无线射频频段,默认为2.4GHZ;设置电源放大倍数主要是为了设置无线数据传输的有效距离;指定写管道是由于NRF24L01可以通过设置不同的管道地址,使其支持点对多通信,故在数据通信前,必须提前指定数据发送端的通信地址;指定管道后,使用该管道将数据写入NRF24L01缓冲区,数据便可以通过无线射频的方式自动发送给接收端,整个发送过程完全透明。数据接收端为了可以区分接收到的数据是温度和湿度值,在使用NRF24L01发送数据前分别对温湿度进行预处理,程序中定义的temp和humi变量都是unsigned long型,它们的范围都为0 to 4,294,967,295 (2^32 - 1),分别给测到的temp加上1000,给humi加上10000,Raspberry Pi服务器端便可以根据他们的范围区分温度和湿度值。通信过程完整程序设计见附录二中Arduino通过NRF24L01 发送温湿度部分:
图2.13 Arduino与NRF24L01程序设计流程图
Raspberry Pi端程序设计流程图如图2.14所示,主要过程为打开SPI通信、设置重新连接时间与次数、指定读管道、打开无线射频侦听、数据写入缓冲区、数据还原处理、数据写入文件。打开SPI通信,包括SPI驱动初始化使Arduino能够通过GPIO口设别SPI设别、指定无线射频频段,需要设置为与Arduino发送端相同的频段的,即依然采用默认设置2.4GHz;设置重新连接时间与次数可以有效避免接收端陷入无限等待状态,假如在规定的时间内没有接收到数据,NRF24L01将自动切换到待机模式,减少能量消耗;指定读管道需要设置该管道与Arduino传感器节点发送端管道相同,以保证Raspberry Pi接收端能够接收到发送端发送过来的数据;当上面的设置都完成,便可以打开无线射频侦听,等待数据发送;侦听到数据后便将数据写入缓冲区,以便后面对数据进行处理;由于在发送Arduino传感器节点发送端,分别对温度和湿度值进行了预处理,因此在Raspberry Pi数据节点端需要对数据做相反的数据处理操作,以保证数据测得的温度和湿度值是真实的;接收端NRF24L01接收到的数据时保存在缓冲区中,一旦断电,数据变化会全部丢失,为了避免数据意外丢失,将接收到的数据写入到即数据节点即文件中。完整Raspberry Pi数据节点数据接收程序代码见附录二中Raspberry Pi端接收温湿度部分:
为了避免HTTP服务在读取文件内容即温度值和湿度值造成混乱,故分别将温度值和湿度值保存到不同的文件中。由于Raspberry Pi的内存受限于物理存储空间,假如不断的将数据写入文件,系统长时间运行,文件会变得非常庞大,直接导致内存溢出,因此必须对写入文件数据大小做限制,即流程图2.15、2.16中的监测数据个数是否大于100,假如大于100,则将文件中的数据全部清除。完整的文件的文件写入过程包括打开文件、写入文件、关闭文件。其中写入文件可以按照不同的模式去写入,比如当数据量小于100时以追加的模式写入,当数据量大于100时以全部重写的模式写入。完整文件写入程序代码设计见附录二中Raspberry Pi端接收温湿度部分。
基于B/S架构的远程用户监测子系统中前端显示实际上是一个人机交互的界面程序,用户与浏览器进行交互,界面程序能够将传感器数据节点中的信息实时地显示给用户。课题中监测的数据有温度和湿度,在前端,用户应该可以通过正确的操作步骤后要能够查看到实际传感器节点测量得到的数据。故用户监测子系统在整个远程监测系统设计中对于数据显示有至关重要的作用。
在前端程序设计中,除了让用户能监测到实际的远程数据,也应该对用户的合法性进行验证,系统不对用户的合法性进行判断,则任意用户都可以查看到数据节点中的数据,这便会造成系统数据信息泄露,对整个系统的安全性非常不利。
用户可以在局域网中实现远程访问,这是整个远程监测子系统的基本要求,但是现在用户对远程访问需求更多的是在通过公网进行远程访问服务器,而不是局限在局域网内的远程访问服务器。本课题中将采用VPS反向代理技术,使用这种技术,可以有效实现内网穿透,使用户从Internet直接访问内网服务器。
数据节点保存传感器节点发送的数据后,只能在本地查看。因此必须加入远程通信功能,将数据节点放置到HTTP服务器中,用户可以在局域网中直接通过浏览器去访问所需的数据。浏览器端的网页采用超文本标记语言HTML 结合层叠式样式表CSS来设计远程监测设计静态页面,数据交互部分包括远程用户合法性认证、数据动态调用采用超文本预处理器PHP语言来设计开发。
HTML的全称为Hyper Text Markup Language,他是一种用于创建网页的标准标记语言,网络浏览器可以读取HTML文件,并将其渲染为可视化的网页。HTML允许嵌入图片与对象,并且可以用于创建交互式的表单。课题中的前端登入页面便将使用HTML来开发,并通过表单的方式与用户进行交互,对用户的身份合法性进行认证。由于只使用HTML来开发前端,浏览器渲染后的效果不是很人性化,故前端设计中将通过CSS技术来对前端进行再次修饰渲染。CSS全称为Cascading Style Sheets,使用CSS技术可以对HTML中特定元素外观进行修饰,比如以何种大小、粗细、颜色、位置等重新渲染,使最终浏览器呈现出来的网页更加人性化。
PHP全称为Hypertext Preprocessor即超文本预处理器,他是一种比较常用的开源计算机脚本语言,特别适合于网络开发中的动态页面开发,而且可以运行在多种网页服务器与操作系统上。课题中通过登入首页中国使用HTML表单的方式与用户交互,将用户输入的数据提交给PHP处理,然后PHP再将处理结果返回给用户,这样便可以实现网页具备动态效果,使用户界面更加生动。PHP的安装使用基于源安装方式,即终端输入apt-get install php,便可以自动安装和PHP相关的所依赖包程序。
Apache是一种开放源代码的网页服务器软件,由于他的跨平台和安全性高特点,并且可以支持多种街解释器比如PHP、Python、Perl等,因此被广泛地使用,是现在最流行的web服务器软件之一。因此课题中将选择Apache作为服务器作为中间件移植到Raspberry上,但由于Apache的功能模块较大,占用系统空间较大,相对于嵌入式设备Raspberry来说,空间负载较大,因此为避免不必要的因内存不足等问题造成不必要的系统故障,给Raspberry安装一个内存较大的SD卡,课题中选择的SD卡内存大小为32G。Apache的安装同样使用基于源安装的方式,在终端中安装与启动的具体操作如下:
1)安装Apache
[email protected] ~$ sudo apt-get install apache2
2)启动Apache服务器:
[email protected] ~$ sudo service apache2 start
3)设置Apache开机自启:
[email protected] ~$ sudo /etc/init.d/apache2 start
3.2.4 开发工具SublimeText和PHPStudy
Sublime Text是一套跨平台的文本编辑器,可以支持多种编程语言,并且支持语法高亮显示,代码自动补全等特色,系统设计中使用的HTML、CSS、PHP三种开发语言Sublime Text都内置支持,因此可以在整个项目中减少因学习工具使用花费不必要的时间。
由于嵌入式设备Raspberry Pi系统自身性能的限制,HTTP服务器端开发调试不适合在Raspberry Pi上进行,为解决这个问题,课题中将利用PC机的系统运行效率高的优势,在Windows的PC机上搭建一个服务器运行环境,当系统全部开发结束,再将系统移植到Raspberry Pi上。课题中使用的测试服务器环境为 PHPStudy,他是一个PHP调试环境的程序集成包,可以免去服务器运行的系统环境设置等繁琐步骤,开发工具如下图3.1所示。
图3.1 phpstudy集成环境
Web监测子系统结构框架如图3.2所示。首先是主页即远程登入页面,在此登入页面对用户进行身份认证,合法用户则可以进入数据统一查询界面,选择需要查看的远程数据,即温度或则湿度数据,数据显示界面通过调用数据节点中已保存的数据,然后显示给用户。
图3.2 Web监测子系统
1)远程登入页面设计:
登入页面设计主要目的是为了实现一个能与用户交互并可以对用户合法性认证的功能,完整的登入页面程序见附录,实际登入效果如图3.3所示,其中核心的用户认证表单程序设计如下,通过post方式将用户输入的用户和密码提交给后端action.php合法性判断文件,在action.php中验证用户的合法性。完整登入页面程序设计见附录三index.html。
<form action="php/action.php" method="post">
用户名:<input type="text" name="username" size="20"></br>
密码: <input type="password" name="pd" size="20"></br>
<div id="but" ><input type="submit" name="button" value="确定"></div>
</form>
图3.3 远程登入页面
2)统一查询页面程序设计:
设计统一查询页面,是为了对所有远程监测数据进行统一的管理与显示,当用户处于此页面时,能够方便的查看指定环境数据,其核心程序设计如下。完整程序设计见附录三jiankong.php。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>监控页面</title>
<style>
body {background-image:url("img/bg.png");}
p.a {color:red;}
</style>
</head>
<body >
<div class="readme">
<p class="a">Select the paramenters you want to qury and click the links below!!!</p>
</div>
<div class="temperature">
<a href="/php/temperature.php">Current Temperature</a>
</div>
<div class="humidity">
<a href="/php/humidity.php">Current Humidity</a>
</div>
</body>
</html>
图3.4 远程监控页面
当用户点击Current Temperature,程序便会打开当前目录下/php/temperature.php文件,temperature.php为输出当前温度程序,输出结果如图3.4所示,点击Current Humidity,程序便会打开当前目录下/php/humidity.php文件
用户合法性认证程序如下,由于通过HTTP协议是一种无状态协议,无法对当前用户状态进行持续跟踪,因此在认证程序中加入PHP的session机制,他可以对用户当前的状态进行跟踪,具体实现方式如下,首先在程序开始位置设置session_start()启动session,获取然后获取用户提交的用户名与密码,假如用户名或则密码为空则输出提示信息用户名或密码不能为空,并通过$_SESSION['userflag']设置其值为0,假如用户名和密码都为root,通过$_SESSION['userflag']设置其值为1,并将页面跳转到jiangkong.php页面,否则设置$_SESSION['userflag']值为0,提示用户用户名或密码错误。
<?php
session_start();
header('Content-Type:text/html;charset=utf8');
$username=$_POST["username"];
$password=$_POST["pd"];
if ($username==""|| $password=="") {
$_SESSION['userflag']=0;
echo "<script>alert('用户名或密码不能为空');</script>";
}elseif ($username=="root"&&$password=="root") {
$_SESSION['userflag']=1;
echo"<script>alert('欢迎登入$time1');window.location.href='jiankong.php'</script>";
}else{
$_SESSION['userflag']=0;
echo "<script>alert('用户名或密码错误');window.location.href='index.html'</script>";
}
?>
反向代理是指以代理服务器来接受网络上连接请求,然后将请求转发给内部网络上的服务器,并将从服务器的结果返回给网络上连接的客户端。整个过程如图3.5所示,Raspberry Pi上的HTTP服务器处于局域网中,他将流量全部转发到代理服务器65.49.228.60,当用户通过浏览器访问地址http:// 65.49.228.60,便间接地访问了处于局域网中HTTP服务器。
图3.5 反向代理
课题中使用ssh作为反向代理工具,SSH是Secure Shell的简称,一种加密的网络传输协议,默认的linux系统中都会安装,因此可以避免额外的软件安装,和SSH反向代理的相关参数如下:
-f :后台认证用户/密码,通常和-N连用,不用登录到远程主机。
-N :不执行脚本或命令,通常与-f连用。
-g :在-L/-R/-D参数中,允许远程主机连接到建立的转发的端口,如果不加这个参数,只允许本地主机
-R:将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口,即上面命令中的8888端口
-p: 被登录的ssd服务器的sshd服务端口
具体实现步骤如下:
1)、Raspberry Pi通过网关连接网络;
2)、从ISP服务商处购买VPS,获取公网IP地址,本项目中的IP地址为65.49.228.60;
3)、在Raspberry Pi上开启SSH端口转发功能,在终端输入如下命令开启端口转发功能:ssh –f –N –g –R 8888:127.0.0.1:80 [email protected] –p 27197 ,输入远程SSH登入密码,如图3.6所示。
图3.6 ssh反向代理
执行上面的端口转发命令,访问http://65.49.228.60:8888就相当于访问http://127.0.0.1:80 。至此,使用VPS结合SSH端口转发技术便实现了反向代理的功能。
系统测试是整个系统在设计和开发中的重要组成部分,是保证整个系统性能和质量的重要步骤。本系统按照数据的流向可以分为传感器子系统,数据节点子系统,远程访问子系统。下面将把整个系统部署到最真实的环境下,按照数据流向进行每个模块测试。考虑到系统部署与公网,很有可能遭到非法攻击,造成系统瘫痪。因此,除了对系统核心功能的测试外,还需要对系统的安全性进行测试。
传感器节点测量温度和湿度,测试结果如下图4.1所示,串口输出的温度值为1026,湿度值为10085,故实际温度为27℃,实际湿度为79%。
图4.1 温湿度采集结果
在Raspberry Pi上在终端接收数据如下图4.2所示,接收到的温度为温度为27℃,实际湿度为79%,与传感器节点端单独测试的结果一致,说明在使用NRF24L01进行传感器节点与数据节点端的通信过程中数据并没有发生意外错误,因此在局域网中的数据通信设计是完全成功的。
图4.2 终端接收数据
启动传感器节点与Raspberry Pi并开启上的HTTP服务器,通过终端开启SSH端口转发,使用URL地址http://65.49.228.60:8888访问web服务远程web页面,结果如下图4.3所示,可见基本的公网远程访问功能已经实现。
图4.3 浏览器远测登入界面
在web页面中输入正确用户名root和密码root成功进入系统,如4.4图所示,设法改变相应温度和湿度,点击要查询温度,成功显示温度,并可以看出温度值由原来29摄氏度变为30摄氏度 如图4.5所示,点击查询湿度,成功显示湿度,并可以看出湿度值由原来71%变为95%,如图4.6所示,因此通过远程访问,随着温度和湿度变化,监测页面的温度和湿度也相应变化,即整个远程数据监测系统的基本功能便已经成功实现。
图4.4 远程参数查询界面
图4.5 温度查询 图4.6 湿度查询
对于远程监测系统,实现功能的正常运行是远远不行的,如果直接将一套没有经过安全性评估测试的远程监测系统放在公网上运行,那么非常容易遭受非法攻击。由于整个监测系统的核心数据节点和传感器节点是部署与内网的,假如攻击者通过处于公网的VPS间接进入内网,那么便会造成严重的内网攻击事件。因此,除了对整个系统的功能性测试外,对系统的安全性进行一定的评估也是非常必要。
由于整个系统是自己设计与实现的,因此站在开发者的角度可能会无法意识到潜在的安全问题,想要保证系统的绝对安全是比较困难的。但是我们站在攻击者的角度对系统安全性进行测试,假如攻击者在现系统环境下无法对系统进行破坏,我们便可以间接地认为系统是安全的。这种站在攻击者的角度对系统进行安全测试的过程我们在安全测试领域被称为“渗透测试”,这种测试手段在现代网站测试中被广泛使用。
渗透测试标准的流程可以分为前期、中期、后期三部分,前期包括技术侦查,社会工程侦查,分析建模,公开漏洞匹配四个过程,中期包括漏洞挖掘和分析,后期包括进阶测试,证据收集,风险评估,生成报告四个部分,由此可见整个测试过程是比较繁琐的,由于系统是有自己设计和开发的,因此我们可以有针对性的进行系统安全测试,按照常见系统漏洞一一验证本系统是否存在安全问题,具体的常见漏洞见附录渗透测试检测项,总共分为10个大项95个小项,基本全覆盖了系统可能出现的安全问题。按照附录上的常见漏洞对系统测试后发现的系统主要漏洞如下:
1)未授权访问
数据节点文件temperature.txt与humidity.txt被放置与web站点目录下,可以在未授权的情况下直接构造URL对目标文件进行访问,如下图4.7所示:
漏洞修复方法:将数据节点文件放置移动到web站点外任意路径,此时再去访问刚刚的URL,便显示无法访问,如图4.8所示
图4.7 未授权访问
图4.8 未授权访问已修复
2)用户名简单,密码弱口令
在系统开发时,为了测试的方便,设置了用户名和密码都为root,这是最常见的弱口令,攻击者可以很容易的猜测到,一旦猜测到了用户名和密码,那么系统的认证机制就形同虚设。
漏洞修复方法:更改用户名和密码,禁止使用弱口令,密码中应该至少应含有大小写字母和数字,是密码无法猜测。
3)敏感信息泄露
使用一款浏览器插件wappalyzer可以清楚的看到,服务器使用的web服务器为Apache2.4.10,操作系统为Raspberry,如图4.9所示。这直接暴露了服务器和操作系统的信息。由于我们的服务器是处于内网中,服务器的所有流量都是从VPS端流出,故这种敏感信息泄露,虽然可能存在潜在安全威胁,但攻击者无法直接与服务器交互,这种漏洞被利用的可能极低。
图4.9 系统敏感信息泄露
本课题设计并完成了一个通用的、基于嵌入式web技术的远程监测系统。本文的具体工具如下:
(1)温湿度采集:通过Arduino控制器结合DHT11传感器可以准确的测量得到温湿度值;
(2)数据节点与B/S搭建:成功在嵌入式设备Raspberry Pi上安装操作系统,使用文件作为数据节点,并通过操作系统来对文件进行管理,同时在操作系统Raspberry上安装了Apache服务器,完成搭建基础的B/S架构;
(3)Arduino和Raspberry Pi通信:使用NRF2401无线转SPI模型成功实现传感器节点与数据节点之间数据通信;
(4)实现远程访问:利用反向代理技术,低成本的实现任意用户可以从公网访问,传感器节点测量得到的数据。
(5)系统安全性检测:在完成系统的基本功能后,以渗透测试的方法对系统漏洞一一检测, 找出系统载开发阶段被忽视的潜在安全问题。
由于时间限制,设计中还存在一些有待改进的不知之处。
(1)远程监测的参数较少,只监测了温度和湿度环境参数,由于客观时间限制,还是可以增加一些其他参数监测;
(2)远程监测的子系统前端设计过于简陋,对监测到的数据没由进行可视化处理,直接输出在了浏览器端,因此可以将数据以图表的形式显示,使它更加形象;
(3)当数据量比较大时,设计中以文件方式作为数据节点将不太合适,可以考虑使用数据库的方式来存储数据;
(4)远程监测,只完成了将数据从传感器节点发送给用户,假如用户也可以发送数据给传感器节点,那么便可以实现远程控制的效果
以上这些问题只留待以后解决,如果有机会将这几个未完成的功能实现,那么系统便是一套很完善的小型远程监测系统。
1)通过串口启动Raspberry Pi:
Raspberry Pi V3版本的串口不再用于开机,因为时钟是由内核提供,时钟晶振被用于蓝牙模块,而内核的时钟不够稳定,因此无法直接通过串口登入Raspberry Pi,为了避免多余的设置,在没有显示屏的情况下,可以采用ssh的方式登入。
2)Raspberry Pi更改键盘布局:
键盘布局不对,Raspberry Pi(raspberry pi)是英国产品,默认键盘布局是英国(GB),我们用的键盘布局一般是美国(US)的dpkg-reconfigure keyboard-configuration 进入后,选通用的101键PC键盘。按照提示,依次更改便可,最后使用tab键确定,如图5.1所示。
图5.1 更改键盘布局
3)更新Raspberry Pi系统时速度很慢:
下载或更新系统文件速度比较慢,主要原因是Raspberry Pi中默认的更新源服务器在国外,因此可以添加一些国内的镜像源。具体操作如下:
使用nano编辑器打开目录/etc/apt/下的sources.list源文件:
sudo nano /etc/apt/sources.list
在原来的代码在增加以下几个国内的镜像下载源:
deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ jessie main non-free contrib
deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ jessie main non-free contrib
int temp;//温度
int humi;//湿度
int tol;//校对码
int j;
unsigned int loopCnt;
int chr[40] = {0};//创建数字数组,用来存放40个bit
unsigned long time;
#define pin 4
void setup()
{
Serial.begin(9600);
}
void loop()
{
bgn:
delay(2000);
//设置4号接口模式为:输出
//输出低电平20ms(>18ms)
//输出高电平40μs
pinMode(pin,OUTPUT);
digitalWrite(pin,LOW);
delay(20);
digitalWrite(pin,HIGH);
delayMicroseconds(40);
digitalWrite(pin,LOW);
//设置4号接口模式:输入
pinMode(pin,INPUT);
//LOW电平响应信号
loopCnt=10000;
while(digitalRead(pin) == LOW)
{
if(loopCnt-- == 0)
{
//如果长时间不返回高电平,输出个提示,重头开始。
Serial.println("HIGH");
goto bgn;
}
}
//HIGH电平响应信号
loopCnt=30000;
while(digitalRead(pin) == HIGH)
{
if(loopCnt-- == 0)
{
//如果长时间不返回低电平,输出个提示,重头开始。
Serial.println("LOW");
goto bgn;
}
}
//开始读取bit1-40的数值
for(int i=0;i<40;i++)
{
while(digitalRead(pin) == LOW)
{}
//当出现高电平时,记下时间“time”
time = micros();
while(digitalRead(pin) == HIGH)
{}
//当出现低电平,记下时间,再减去刚才储存的time
//得出的值若大于50μs,则为‘1’,否则为‘0’
//并储存到数组里去
if (micros() - time >50)
{
chr[i]=1;
}else{
chr[i]=0;
}
}
//湿度,8位的bit,转换为数值
humi=chr[0]*128+chr[1]*64+chr[2]*32+chr[3]*16+chr[4]*8+chr[5]*4+chr[6]*2+chr[7];
//温度,8位的bit,转换为数值
temp=chr[16]*128+chr[17]*64+chr[18]*32+chr[19]*16+chr[20]*8+chr[21]*4+chr[22]*2+chr[23];
//校对码,8位的bit,转换为数值
tol=chr[32]*128+chr[33]*64+chr[34]*32+chr[35]*16+chr[36]*8+chr[37]*4+chr[38]*2+chr[39];
//输出:温度、湿度、校对码
if(tol=humi+tol){ //理论上,湿度+温度=校对码 ,如果数值不相等,说明读取的数据有错。
Serial.print("temp:");
Serial.println(temp);
Serial.print("humi:");
Serial.println(humi);
}
}
#include <SPI.h>
#include "RF24.h"
RF24 radio(7,8); //RF24(uint16_t _cepin, uint16_t _cspin, uint32_t spispeed );
byte addresses[][6] = {"1Node","2Node"};
unsigned long temp;//温度
unsigned long humi;//湿度
unsigned long tol;//校对码
int j;
unsigned int loopCnt;
int chr[40] = {0};//创建数字数组,用来存放40个bit
unsigned long time;
#define pin 4
void setup() {
Serial.begin(115200);
radio.begin(); //bool begin(void); Checks if the chip is connected to the SPI bus
radio.setPALevel(RF24_PA_LOW); //void setPALevel ( uint8_t level ); Set Power Amplifier (PA) level to one of four levels: RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
StartListening();//void startListening(void);
}
void loop() {
bgn:
delay(2000);
//设置4号接口模式为:输出
//输出低电平20ms(>18ms)
//输出高电平40μs
pinMode(pin,OUTPUT);
digitalWrite(pin,LOW);
delay(20);
digitalWrite(pin,HIGH);
delayMicroseconds(40);
digitalWrite(pin,LOW);
//设置4号接口模式:输入
pinMode(pin,INPUT);
//LOW电平响应信号
loopCnt=10000;
while(digitalRead(pin) == LOW)
{
if(loopCnt-- == 0)
{
//如果长时间不返回高电平,输出个提示,重头开始。
Serial.println("HIGH");
goto bgn;
}
}
//HIGH电平响应信号
loopCnt=30000;
while(digitalRead(pin) == HIGH)
{
if(loopCnt-- == 0)
{
//如果长时间不返回低电平,输出个提示,重头开始。
Serial.println("LOW");
goto bgn;
}
}
//开始读取bit1-40的数值
for(int i=0;i<40;i++)
{
while(digitalRead(pin) == LOW)
{}
//当出现高电平时,记下时间“time”
time = micros();
while(digitalRead(pin) == HIGH)
{}
//当出现低电平,记下时间,再减去刚才储存的time
//得出的值若大于50μs,则为‘1’,否则为‘0’
//并储存到数组里去
if (micros() - time >50)
{
chr[i]=1;
}else{
chr[i]=0;
}
}
//湿度,8位的bit,转换为数值
humi=chr[0]*128+chr[1]*64+chr[2]*32+chr[3]*16+chr[4]*8+chr[5]*4+chr[6]*2+chr[7];
//温度,8位的bit,转换为数值
temp=chr[16]*128+chr[17]*64+chr[18]*32+chr[19]*16+chr[20]*8+chr[21]*4+chr[22]*2+chr[23];
//校对码,8位的bit,转换为数值
tol=chr[32]*128+chr[33]*64+chr[34]*32+chr[35]*16+chr[36]*8+chr[37]*4+chr[38]*2+chr[39];
//输出:温度、湿度、校对码
if(tol=humi+tol){ //理论上,湿度+温度=校对码 ,如果数值不相等,说明读取的数据有错。
Serial.print("temp:");
temp=temp+1000;
Serial.println(temp);
Serial.print("humi:");
humi=humi+10000;
Serial.println(humi);
}
radio.write( &temp, sizeof(unsigned long) );
radio.write( &humi, sizeof(unsigned long) );
// Try again 1s later
delay(1000);
}
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>
#include <RF24/RF24.h>
#include <fstream>
using namespace std;
RF24 radio(22,0);
unsigned int i=0;
unsigned int j=0;
const uint8_t pipes[][6] = {"1Node","2Node"};
int main(int argc, char** argv){
std::fstream fs;
bool role_ping_out = true, role_pong_back = false;
bool role = role_pong_back;
radio.begin();
radio.setRetries(15,15);
radio.openReadingPipe(1,pipes[1]);
radio.startListening();
while (1)
{
if ( radio.available() )
{
unsigned long got;
while(radio.available()){
radio.read( &got, sizeof(unsigned long) );
}
if(got<10000)
{
got=got-1000;
printf("Got temperatur: %lu℃ \n", got);
j=j+1;
if(j>100)
{
j=0;
fs.open("/var/www/html/txt/temperature.txt",std::fstream::in |std::fstream::out |std::fstream::trunc);
fs<< got+1000;
fs<< "\n";
fs.close();
delay(925); //Delay after payload responded to, minimize RPi CPU time
}
else{
fs.open("/var/www/html/txt/temperature.txt",std::fstream::app );
fs<< got;
fs<< "\n";
fs.close();
delay(925); //Delay after payload responded to, minimize RPi CPU time
}
}
else{
got=got-10000;
printf("Got humidity: %lu% \n",got);
i=i+1;
if(i>100)
{
i=0;
fs.open("/var/www/html/txt/humidity.txt",std::fstream::in |std::fstream::out |std::fstream::trunc);
fs<< got;
fs<< "\n";
fs.close();
delay(925); //Delay after payload responded to, minimize RPi CPU time
}
else
{
fs.open("/var/www/html/txt/humidity.txt",std::fstream::in |std::fstream::out | std::fstream::app );
fs<< got;
fs<< "\n";
fs.close();
delay(925); //Delay after payload responded to, minimize RPi CPU time
}
}
}
}
return 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>access</title>
<style type="text/css">
body {
background-image:url("img/bg.png");
}
.dengru {
position: absolute;
left: 35%;
right: 0;
bottom: 65%;
height: 0;
font-size: 25px;
}
#but{
position: absolute;
left: 35%;
right: 0;
bottom: 60%;
height: 0;
}
</style>
</head>
<body >
<div class="dengru">
<div class="two" style="height:100%">
<form action="php/action.php" method="post">
用户名:<input type="text" name="username" size="20"></br>
密 码: <input type="password" name="pd" size="20"></br>
<div id="but" ><input type="submit" name="button" value="确定"></div>
</form>
</div>
</div>
</body>
</html>
action.php:
<?php
session_start();
header('Content-Type:text/html;charset=utf8');
$time1=date("h:i:sa");
//$time2=
$username=$_POST["username"];
$password=$_POST["pd"];
$_SESSION['username']=$username;
$_SESSION['password']=$password;
if ($username==""|| $password=="") {
$_SESSION['userflag']=0;
echo "<script>alert('用户名或密码不能为空');</script>";
}elseif ($username=="root"&&$password=="root") {
$_SESSION['userflag']=1;
echo "<script>alert('欢迎登入,当前登入时间为:$time1');window.location.href='../jiankong.php'</script>";
}else{
$_SESSION['userflag']=0;
echo "<script>alert('用户名或密码错误');window.location.href='../index.html'</script>";
}
?>
humidity.php:
<?php
session_start();
if(!isset($_SESSION['userflag'])){
echo "<script>alert('你没有权限访问');window.location.href='../index.html'</script>";
}
header("Content-Type:text/html; charset=utf-8");
$lines=file("../../txt/humidity.txt");
foreach($lines as $line)
{
echo "Current humidity:$line%";
echo "<br>";
} //humidity
?>
temperature.php:
<?php
session_start();
if(!isset($_SESSION['userflag'])){
echo "<script>alert('你没有权限访问');window.location.href='../index.html'</script>";
}
header("Content-Type:text/html; charset=utf-8");
$lines=file("../../txt/temperature.txt");
foreach($lines as $line)
{
echo "Current temperature:$line ℃ ";
echo "<br>";
} //temperature
?>
jiankong.php:
<?php
session_start();
if(!isset($_SESSION['userflag'])){
echo "<script>alert('你没有权限访问');window.location.href='index.html'</script>";
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>监控页面</title>
<style>
body {background-image:url("img/bg.png");}
p.a {color:red;}
</style>
</head>
<body >
<div class="readme">
<p class="a">Select the paramenters you want to qury and click the links below!!!</p>
</div>
<div class="temperature">
<a href="temperature.php">Current Temperature</a>
</div>
<div class="humidity">
<a href="humidity.php">Current Humidity</a>
</div>
</body>
</html>
Arduino Uno |
1块 |
Raspberry Pi3 |
1块 |
DHT11 |
1个 |
NRF24L01 |
2块 |
32G TF卡 |
1张 |
USB读卡器 |
1个 |
路由器 |
1台 |
Arduino USB下载线 |
1根 |
双绞线 |
1根 |
显示屏 |
1台 |
HDMI转VGA接口线 |
1根 |
Raspberry Pi R3 电源线 |
1根 |
有独立IP地址的VPS |
1台 |
导线 |
若干 |
参考文献
[1]刘金梅.基于B/S架构的嵌入式Web远程监控系统的研究与实现[D].内蒙古大学,2012.
[2]周维.基于 Web 技术的智能家居控制系统的设计与实现[D].西安电子科技大学,2014.
[3]邵文. 基于Web的远程测控系统的设计[D].东北大学.2010.
[4] 弓雷. ARM 嵌入式 Linux 系统开发详解[M]. 北京:清华大学出版社, 2014. [5] 孙弋. ARM-Linux 嵌入式系统开发基础[M]. 西安:西安电子科技大学出版社, 2015.
[6] 刘刚, 赵剑川. Linux 系统移植(第二版)[M]. 北京:清华大学出版社, 2014. [7] 聂和平.基于ARM9 的嵌入式 Linux 系统移植与驱动开发[D]. 南京:南京邮电大学, 2013.
[8] 金平. 基于嵌入式 Linux 的智能视频监控系统的设计与实现[D]. 长沙:中南大学, 2013.
[9] 邱光能. 基于嵌入式的远程视频监控系统的设计与实现[D]. 长沙:湖南大学, 2013.
[10] 荀攀. Web 远程视频监控智能报警系统的设计[D]. 成都:西南交通大学硕, 2012.
[11] 陈宇. 一种基于嵌入式 Linux 的远程视频监控系统的研究与实现[D]. 沈阳工业大学, 2011.
[12] 陈晓伟. 基于 WEB 网络视频监控系统的客户端软件的设计与实现[D]. 杭州:浙江工业 大学, 2014.
[13] 陈矗, 任平红. Web 编程基础:HTML、CSS、JavaScript[M]. 北京:清华大学出版社, 2014.
[14] 杨习伟. HTML5+CSS3 网页开发实战精解[M]. 北京:清华大学出版社, 2014. [15] 于坤. JavaScript 基础与案例开发详解[M]. 北京:清华大学出版社, 2014.
[16] 王云华,智能家庭网络系统研究硕士学位论文南京:南京信息工程大.
学,2011
[17] 王学龙,嵌入式系统设计与应用北京:清华大学出版社,2001.
[18] 窦炎,现代家居设计与家居智能系统的应用研究.包装工程,2014
[19] 俞皖卿,智能家居终端的研究与设计.[D].上海:上海交通大学,2012
[20] 杨浩杰,智能家居远程监控系统的研究与实现.[D].上海:东华大学.2011
[21] 羡慧竹,基于物联网的智能网关系统研究与实现.[D].北京:北京工 业大学,2014.
[22] 彭赓.基于改进网络爬虫技术的 SQL 注入漏洞检测[J].计算机应用研究.2010
[23] 白会肖.Web 应用程序下 XSS 漏洞攻击与防御研究[J].石家庄职业技术学院学 报,2012,(6).
[24] 刘合叶.多功能 SQL 注入检测系统的实现及攻击防范方法研究[D].北京:北京交通大 学,2009.
[25] 宋海龄,文伟平. 一个典型的 Web 安全评测工具的分析与改进. 技术研究, 2011
[26] 闫波波. Web 应用安全渗透测试工具的设计与实现:[硕士学位论文]. 天津: 天津 大学,2012
[27] 张宗之. 基于爬虫技术的web应用漏洞挖掘的研究:[硕士学位论文]. 北京: 北京 邮电大学,2013
[28] 宁玉可. 基于BS架构的光伏远程监控系统的设计与实现[D]. 南京理工大学:宁玉可, 2017.
[29] 陈志祥. 基于Linux和web远程监控报警系统的设计[D]. 昆明理工大学 :陈志祥, 2014.
[30]邓蓓. 智能粮仓的采集终端的设计与应用[D]. 电子技术与软件工程, 2014.
[31]祝文静. 基于GPRS无线通讯的便携式气象仪的设计与实现[D]. 安徽理工大学, 2013.
[32]白晓亮. 基于嵌入式Linux系统的无线智能家居控制系统的设计与实现[D]. 河北大学, 2014.
[33]马苗苗. 无线传感器网络在油田中的应用研究[D]. 东北石油大学, 2010.
[34]雷瑞庭 宋跃. 单总线传感器接口Verilog的设计与实现[D]. 东莞理工学院学报, 2013.
[35]刘湘云. 炎陵黄桃大棚温湿度采集终端设计[D]. 中南林业科技大学, 2014.
[36]陈龙 张志达. 基于AVR多功能报警系统的温湿度模块的设计[D]. 自动化技术与应用, 2011.
[37]杨芳明. 基于ARM的草莓园环境监管控制算法研究[D]. 南昌航空大学, 2013.
[38]毛明轩 朱皋 杨守良. 基于单片机的温湿度感应智能晾衣杆系统设计[D]. 重庆文理学院学报(自然科学版), 2011.
[39]岳静. ZigBee温湿度数据采集系统研究[D]. 煤炭技术, 2011.
[40]唐正柱. 一种基于OSGI的智能家庭短信平台的设计与实现[D]. 西安电子科技大学, 2012.
[41]李德路 侯文宝. 基于DHT11室内温湿度监控系统设计[D]. 智能建筑与城市信息, 2013.
[42]倪天龙. 单总线传感器DHT11在温湿度测控中的应用[D]. 单片机与嵌入式系统应用, 2010.
[43]陈静. 基于单片机的温度湿度控制系统设计[D]. 科技信息, 2011.
[44]靳江伟. 基于ARM的智能家居综合控制系统设计与实现[D]. 沈阳理工大学, 2011.
[45]程永辉. 无线传感器的研究与实现[D]. 武汉理工大学, 2010.
[46]姚世凤. 基于电力载波的温室监测系统设计[D]. 西南大学, 2012.
[47]王赫 李小波 陈培 罗浩鑫. 基于压力感应的地铁车厢智能通风系统[D]. 轻工科技, 2014.
[48]唐金海. CAN总线分析及应用编程[D]. 内蒙古大学, 2013.
[49]杨洋 朱彩莲. 温室自动喷灌系统设计[D]. 湖南城市学院学报(自然科学版), 2010.
[50]胡颖. 基于无线传感器网络的山体滑坡监测预警系统设计与研究[D]. 重庆大学, 2011.