整体概述
本项目基于“物联网技术与应用”课程的学期大作业。
esp8266收集dht11的温湿度数据通过mqtt发布,并订阅web端发送的数据打印到SSD1306的OLED显示屏上,web端通过echarts来显示收到的数据,并可以发布数据给esp8266端。
MQTT服务器搭建
这里使用阿里云服务器,所以要事先购买一个阿里云服务器。
下载EMQ X Broker的安装包到阿里云服务器上。
可以去emq的官网下载对应版本的EMQ X Broker
官网地址:https://www.emqx.io/cn/
这里下载v4.0-rc.3的版本
下载好后可以通过Xshell将安装包上传到阿里云(具体的上传过程就不写了,网上有很多教程)
上传成功后可以在阿里云上看到之前下载的安装包
输入下面的命令来安装emq x
sudo rpm -ivh emqx-centos7-v4.0-rc.3.x86_64.rpm
安装成功后输入以下命令启动
emqx start
启动成功后还没完,还要去安全组打开相应的端口。
去阿里云的安全组打开相应端口,分别为8083、1883、18083这三个端口
点击配置规则打开安全组规则配置的界面
添加三个安全组规则,其中端口范围就是上述的三个端口,授权对象可以填你允许或拒绝访问的对象,0.0.0.0/0表示所有对象
添加完后再重启服务器,mqtt服务器就搭建好了(当初因为没有重启服务器,测试了好久都不成功)
IoT端实现
我使用的库是simpleDHT11.h、PubSubClient.h和SSD1306Wire.h
int pinDHT11 = 5;//dht11的pin脚
SimpleDHT11 dht11(pinDHT11);
const char* ssid = "******";//wifi账号
const char* password = "*****";//wifi密码
const char* mqtt_server = "*****"; // MQTT服务器
const char* TOPIC = "*****"; // 订阅信息主题
const char* client_id = "*****"; // 标识当前设备的客户端编号
int linePx = 11;//规定打印的行
WiFiClient espClient; // 定义wifiClient实例
PubSubClient client(espClient); // 定义PubSubClient的实例
SSD1306Wire display(0x3c, D4, D5);//设置OLED屏相关数据
setup函数
void setup() {
display.init();初始化OLED屏
Serial.begin(115200);
setup_wifi();//连接wifi
client.setServer(mqtt_server, 1883); //设定MQTT服务器与使用的端口,1883是默认的MQTT端口
client.setCallback(callback); //设定回调方式,当ESP8266收到订阅的消息时会调用此方法
}
loop函数
void loop() {
display.drawString(0, 0, "Broker Message:");
display.display();
if (!client.connected()) {
reconnect();
}
client.loop();
// read without samples.
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("Read DHT11 failed, err=");
Serial.println(err);
delay(1000);
return;
}//读取DHT11上的温湿度数据
int temp = (int)temperature;
int hum = (int)humidity;
char json[100];
sprintf(json,"%s%d%s%d%s","{\"temp\":\"",temp,"\",\"hum\":\"",hum,"\"}");//以json的格式发布消息
Serial.print("Send Message:");
Serial.print(json);
Serial.print("\n");
client.publish("******",json);//以自定义的主题发布消息
//DHT11 sampling rate is 1HZ
delay(2000);
}
连接mqtt服务器函数
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(client_id)) {
Serial.println("connected");
// 连接成功时订阅主题TOPIC
client.subscribe(TOPIC);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
回调函数callback
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String a="";
//接受订阅主题的消息
for (int i = 0; i < length; i++) {
a = a+(char)payload[i];
Serial.print((char)payload[i]);
}
Serial.println();
if(linePx<45){
display.drawString(0, linePx, a);
linePx += 11;
}else{
display.drawString(0, 50, "Too many Messages");
}
Serial.println(linePx);
display.display();//每打印一行,为了避免后面与前面打印的重叠,需要增加打印所在的行数linePx
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
} else {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
}
}
Web端实现
web端采用了websocke和echarts的js文件来实现
echarts的js文件名
echarts.min.js
websocket的js文件名
mqttws31.min.js
其中echarts的js文件可以去官网https://www.echartsjs.com/zh/index.html直接下载
websocket方面代码
连接服务器
client = new Paho.MQTT.Client("服务器地址", Number(8083), "客户端ID");//建立客户端实例
client.connect({onSuccess:onConnect});//连接服务器并注册连接成功处理事件
function onConnect() {
client.subscribe("******");//订阅主题
}
client.onConnectionLost = onConnectionLost;//注册连接断开处理事件
client.onMessageArrived = onMessageArrived;//注册消息接收处理事件
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
alert("连接断开");
}
}
接受并解析json数据
function onMessageArrived(message) {
var obj = JSON.parse(message.payloadString);//将收到的json消息解析
humData = obj.hum;
tempData = obj.temp;//json格式:{"temp":"tempData","hum":"humData"}
}
发布主题消息函数
function SendMessage(){
message = new Paho.MQTT.Message(document.getElementById("sendMessage").value);
message.destinationName = "******"; //发布的主题
client.send(message);
}
关闭websocke连接
function disConnect(){
client.disconnect();
alert("WebSocket连接已关闭!");
}
echarts方面看看官方手册就足够了,需要说明的是,要做到实时刷新的话,新建两个温度湿度的数组,大小自己定,每次有新数据进来时,push后去掉第一个数据即可
Time.push(now);//往时间中添加数据
Temp.push(tempData);//往温度中添加数据
Hum.push(humData);//往湿度中添加数据
if(Time.length>10){
Time.shift();//去掉时间数组中第一个数据
Temp.shift();//去掉温度数组中第一个数据
Hum.shift();//去掉湿度数组中第一个数据
}