在学校的气象社团中,有一项很重要的任务,就是需要每天记录特定时刻里的气象数据,包括了风向、风速、气温、湿度、降雨量等等。其中测量空气的温度和湿度的仪表一般是放在操场外草坪上百叶箱中,包括了温度表、湿度表、最高和最低温度表等,人工抄表不仅费事,而且在开关百叶箱门时,可能造成数据的破坏。现今已经到了物联网时代,这项工作早就可以用远程抄表的方式替代了。本项目实现了温湿度的远程抄表功能。
首先是选取器件:
1)传感器使用DHT11,这个器件已经在https://bbs.21ic.com/icview-3186340-1-1.html中尝试自己写代码逐位读取,本文中直接调用Arduino库。
2)MCU使用ESP8266,ESP8266价格低廉,提供一个非常低速的Wifi接口,但是在本文的要求中是足够用的,本文中的开发环境是Arduino。
3)电池使用普通的3.7V锂电池
其次是选择合适的通信协议:
在这个项目中,实时性要求并不高,数据量也很少,而且在校园中,属于开放Wifi覆盖范围内(但信号质量并不好),可以使用MQTT协议传输数据。
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一个基于客户端-服务器的消息发布/订阅(publish/subscribe)的轻量级通讯协议,一般基于TCP(基于UDP的叫做MQTT-SN),可靠性是有保证的;使用文本形式,固定长度的头部只有2个字节,可以做到低开销、低带宽占用;同时无需应用程序耦合,提供一对多的消息发布,简单、开放、易于实现、可控性好,已经成为IoT中最为广泛的通信协议之一了。
考虑到成本和易于实现,选择了broker.emqx.io作为MQTT的服务器,该服务器支持非认证的用户发布和订阅消息。
具体实现如下:
1)首先是下载和安装arduino环境:
在https://www.arduino.cc/en/Main/Software中下载安装(过程略),由于Arduino缺省没有ESP8266支持,因此还需加入ESP8266的开发板。打开应用程序,在菜单“文件-首选项”对话框的附加开发板管理网址中加入:
http://arduino.esp8266.com/stable/package_esp8266com_index.json
可供选择的MQTT支持库很多,这里选择了Adafruit MQTT Library。
至此,开发环境就搭建好了。
2)硬件连接:
需要把DHT11、ESP8266和电源连接起来,我这里因为都是开发板,因此选择的是杜邦线连接,个人建议使用焊接会更好一些。ESP8266开发板上可供选择管脚比较多,这里使用的是16脚。DHT11直接从ESP8266的开发板上取电。
3)传感器侧的开发:
MQTT的开发从例程改相对简单,选择菜单“文件-示例-Adafruit MQTT Library-mqtt_esp8266”打开例程,并另存一个目录。
将附件Dht11.zip解压出的dht11.c和dht11.h放在上述同一目录下。
文件中增加头文件的引用:
#include "dht11.h"
根据硬件的实际连接修改管脚定义:
#define DHT11PIN 16
根据开放的wifi网络情况,修改WLAN_SSID和WLAN_PASS
根据所选的MQTT server修改相关定义,因为使用匿名连接,所以用户名和关键字都不用填写:
#define AIO_SERVER "broker.emqx.io"
#define AIO_SERVERPORT 1883 // use 8883 for SSL
#define AIO_USERNAME ""
#define AIO_KEY ""
删除掉例程中的订阅部分,修改发布主题为/test:
Adafruit_MQTT_Publish photocell = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/test");
再增加dht11的读取:
因为dht11读取容易失败,所以可以加上校验:
while (DHT11.read(DHT11PIN)!=DHTLIB_OK){
Serial.println("Reading error!");
delay(2000);
Serial.println("Try again...");
}
发布读取信息:
Serial.println("Get values:");
String s1="Humidity (%):";
char t1[10];
dtostrf(DHT11.humidity,2,2,t1);
s1=s1+t1;
String s2="Temperature (oC): ";
char t2[10];
dtostrf(DHT11.temperature,2,2,t2);
s2=s2+t2;
Serial.println(s1);
Serial.println(s2);
MQTT_connect();
bool tran=false;
while(!tran){
bool a=photocell.publish(s1.c_str());
bool b=photocell.publish(s2.c_str());
tran=a and b;
}
Serial.println("ok");
4)电脑侧开发:
在电脑上订阅主题相对简单,使用python代码如下:
import paho.mqtt.client as mqtt
broker = 'broker.emqx.io'
port = 1883
topic = "/test"
def on_connect(client, userdata, flags, rc):
print("Connected with result code: " + str(rc))
def on_message(client, userdata, msg):
print(msg.topic + " " + str(msg.payload.decode('UTF-8')))
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(broker, port, 10)
client.subscribe(topic, qos=0)
client.loop_forever()
运行该python代码,可以得到当前温湿度: