通过使用arduino UNO R3板子获取温湿度模块DHT11中的温湿度然后通过ESP8266WiFi模块发送到MQTT服务器上面,然后再在网页上面显示出来的。这里面涉及一些技术:
Arduino—ESP8266—ESP—连接WiFi、连接MQTT服务器、web显示
前言
通过使用arduino UNO R3板子获取温湿度模块DHT11 中的温湿度然后通过ESP8266WiFi模块发送到MQTT服务器 上面,然后再在网页上面显示出来的。这里面涉及一些技术:
arduino的基本使用:
arduino软件模拟串口的使用(网上资料很多)
DHT11的温湿度读取(有arduino官方库,网上资料也很多)
ESP8266WiFi模块AT指令的使用:
从某宝上面买一块型号为ESP-01的WiFi模块(ESP8266是该类模块的芯片名字)
买来的模块里面已经有程序,上电就可以运行的,一般是官方的AT固件
该官方AT固件,是有使用指导书的,可以问店家要,也可以从官网下载,然后就可以知道怎么用了。
arduino模块的串口引脚(我代码里面的串口引脚是软件模拟的)和买来的ESP-01模块的串口引脚相连接(R-T,T-R),然后再在代码里面,使用串口发送例如“AT+RST\r\n”的指令。
MQTT服务器的部署使用:
一般是要有自己的MQTT服务器的,如果没有,网上也有公共的MQTT Broker可以暂时用一下
网页HTML5的基础知识:
这方面的知识已经是涉及到了网站开发了,但是这个是简单的
你应该要会一个最简单的web后端框架比如python的Flask
然后你就可以把你的网页放在那个后端服务器上,访问那个网站就可以在浏览器上显示出来了
系统概图:
所有的启发来源–国外网站:https://create.arduino.cc/projecthub/thingsboard/temperature-dashboard-using-arduino-uno-esp8266-and-mqtt-5e26eb
需要的库:
arduino的MQTT库:PubSubClient by Nick O’Leary.
arduino的封装好AT指令的WiFi操作库:WiFiEsp by bportaluri
Adafruit Unified Sensor by Adafruit
DHT sensor library by Adafruit
一、连上wifi
一个wifi模块,要想连上网络首先得连上WiFi热点,所以使用AT指令来让WiFi模块连接上SSID。如果你的arduino IDE已经安装了以上那些库,那么就可以把下面的代码拷贝再修改一下 ssid 和 password就可以连接WiFi了。
#include “WiFiEsp.h“ // Emulate Serial1 on pins 6/7 if not present #ifndef HAVE_HWSERIAL1 #include “SoftwareSerial.h“ SoftwareSerial Serial1(6, 7); // RX, TX #endif char ssid[] = “liefyuan“; // your network SSID (name) char pass[] = “123456789”; // your network password int status = WL_IDLE_STATUS; // the Wifi radio’s status void setup() { // initialize serial for debugging Serial.begin(9600); // initialize serial for ESP module Serial1.begin(115200); // initialize ESP module WiFi.init(&Serial1); // check for the presence of the shield if (WiFi.status() == WL_NO_SHIELD) { Serial.println(“WiFi shield not present”); // don’t continue while (true); } // attempt to connect to WiFi network while ( status != WL_CONNECTED) { Serial.print(“Attempting to connect to WPA SSID: “); Serial.println(ssid); // Connect to WPA/WPA2 network status = WiFi.begin(ssid, pass); } Serial.println(“You’re connected to the network”); } void loop() { // print the network connection information every 10 seconds Serial.println(); printCurrentNet(); printWifiData(); delay(10000); } void printWifiData() { // print your WiFi shield’s IP address IPAddress ip = WiFi.localIP(); Serial.print(“IP Address: “); Serial.println(ip); // print your MAC address byte mac[6]; WiFi.macAddress(mac); char buf[20]; sprintf(buf, “%02X:%02X:%02X:%02X:%02X:%02X”, mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); Serial.print(“MAC address: “); Serial.println(buf); } void printCurrentNet() { // print the SSID of the network you’re attached to Serial.print(“SSID: “); Serial.println(WiFi.SSID()); // print the MAC address of the router you’re attached to byte bssid[6]; WiFi.BSSID(bssid); char buf[20]; sprintf(buf, “%02X:%02X:%02X:%02X:%02X:%02X”, bssid[5], bssid[4], bssid[3], bssid[2], bssid[1], bssid[0]); Serial.print(“BSSID: “); Serial.println(buf); // print the received signal strength long rssi = WiFi.RSSI(); Serial.print(“Signal strength (RSSI): “); Serial.println(rssi); }
连接成功(以下的信息是打开串口调试助手,arduino会通过串口打印出来的信息,从中我们可以看到已经连接成功!):
二、真正的干货
问题一:由于波特率导致的ESP-01模块上传数据不成功!这个问题让我痛苦很久,Google、github…各种找———-最后居然是波特率导致!!!!arduino的软串口连接ESP-01wifi模块不适合波特率为115200(出厂时默认设定的!)在AT模式下输入AT+UART_DEF=9600,8,1,0,0修改为9600。修改过后问题全部解决!
结论:PubSubClient这个库是个非常优秀的MQTT库。WiFiESP这个底层是AT指令封装的库也是个非常优秀的库!
代码:
#include “DHT.h“ #include <WiFiEspClient.h> #include <WiFiEsp.h> #include <WiFiEspUdp.h> #include <PubSubClient.h> #include “SoftwareSerial.h“ #define WIFI_AP “liefyuan“ #define WIFI_PASSWORD “123456789” // DHT #define DHTPIN 4 #define DHTTYPE DHT11 char MqttServer[] = “101.200.46.138”; // 初始化以太网客户端对象 — WiFiEspClient.h WiFiEspClient espClient; // 初始化DHT11传感器 DHT dht(DHTPIN, DHTTYPE); // 初始化MQTT库PubSubClient.h的对象 PubSubClient client(espClient); SoftwareSerial soft(2, 3); // RX, TX int status = WL_IDLE_STATUS; unsigned long lastSend; void setup() { Serial.begin(9600); dht.begin(); InitWiFi(); // 连接WiFi client.setServer( MqttServer, 1883 ); // 连接WiFi之后,连接MQTT服务器 lastSend = 0; } void loop() { status = WiFi.status(); if ( status != WL_CONNECTED) { while ( status != WL_CONNECTED) { Serial.print(“[loop()]Attempting to connect to WPA SSID: “); Serial.println(WIFI_AP); // 连接WiFi热点 status = WiFi.begin(WIFI_AP, WIFI_PASSWORD); delay(500); } Serial.println(“[loop()]Connected to AP”); } if ( !client.connected() ) { reconnect(); } if ( millis() - lastSend > 1000 ) { // 用于定时1秒钟发送一次数据 getAndSendTemperatureAndHumidityData(); // 获取温湿度数据发送到MQTT服务器上去 lastSend = millis(); } client.loop(); } / 读取温湿度数据,然后发送到MQTT服务器上去 / void getAndSendTemperatureAndHumidityData() { Serial.println(“Collecting temperature data.”); // 大概250ms读取一次 float h = dht.readHumidity(); float t = dht.readTemperature(); // 查看是否读取温湿度失败的 if (isnan(h) || isnan(t)) { Serial.println(“Failed to read from DHT sensor!”); return; } Serial.print(“Humidity: “); Serial.print(h); Serial.print(“ %\t”); Serial.print(“Temperature: “); Serial.print(t); Serial.print(“ C “); String temperature = String(t); String humidity = String(h); // Just debug messages Serial.print( “Sending temperature and humidity : [“ ); Serial.print( temperature ); Serial.print( “,” ); Serial.print( humidity ); Serial.print( “] -> “ ); // 构建一个 JSON 格式的payload的字符串 String payload = “{“; payload += “\”temperature\”:”; payload += temperature; payload += “,”; payload += “\”humidity\”:”; payload += humidity; payload += “}”; // Send payload char attributes[100]; payload.toCharArray( attributes, 100 ); // boolean publish(const char topic, const char payload); client.publish( “v1/devices/me/telemetry”, attributes ); Serial.print(“[publish]—>>”); Serial.println( attributes ); } void InitWiFi() { // 初始化软串口,软串口连接ESP模块 soft.begin(9600); // 初始化ESP模块 WiFi.init(&soft); // 检测WiFi模块在不在,宏定义:WL_NO_SHIELD = 255,WL_IDLE_STATUS = 0, if (WiFi.status() == WL_NO_SHIELD) { Serial.println(“WiFi shield not present”); while (true); } Serial.println(“[InitWiFi]Connecting to AP …”); // 尝试连接WiFi网络 while ( status != WL_CONNECTED) { Serial.print(“[InitWiFi]Attempting to connect to WPA SSID: “); Serial.println(WIFI_AP); // Connect to WPA/WPA2 network status = WiFi.begin(WIFI_AP, WIFI_PASSWORD); delay(500); } Serial.println(“[InitWiFi]Connected to AP”); } /* MQTT客户端断线重连函数 / void reconnect() { // 一直循环直到连接上MQTT服务器 while (!client.connected()) { Serial.print(“[reconnect]Connecting to MQTT Server …”); // 尝试连接connect是个重载函数 (clientId, username, password) if ( client.connect(“liefyuan“, NULL, NULL) ) { Serial.println( “[DONE]” ); } else { Serial.print( “[FAILED] [ mqtt connect error code = “ ); Serial.print( client.state() ); Serial.println( “ : retrying in 5 seconds]” );// Wait 5 seconds before retrying delay( 5000 ); } } }
自己用Qt5编译出来的MQTT客户端调试软件:
服务器上:
web显示
效果图:
HTML5网页代码:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns=”http://www.w3.org/1999/xhtml“> <head> <meta http-equiv=”Content-Type“ content=”text/html; charset=utf-8“ /> <title>DHT11温湿度WEB显示</title> <script src=”{{ url_for(‘static‘, filename=(‘js/jquery-3.1.1.min.js‘)) }}“></script> <script src=”{{ url_for(‘static‘, filename=(‘js/echarts.common.min.js‘)) }}“></script> <style type=”text/css“> #main-container{ margin-top: 20px; margin-left: 200px; } #main-temp{ width: 400px; height:350px; float: left; border:1px solid red; margin-left: 100px; } #main-humi{ width: 400px; height:350px; float: left; border:1px solid red; margin-left: 100px; } </style> </head> <body> <div id=”main-container“> <div id=”main-temp“></div> <div id=”main-humi“></div> </div> <script src=”https://cdn.bootcss.com/paho-mqtt/1.0.2/mqttws31.min.js“></script> <script type=”text/javascript“> // 基于准备好的dom,初始化echarts实例 var temprature = []; var humidity = []; var myChart = echarts.init(document.getElementById(‘main-temp’)); var mychart2 = echarts.init(document.getElementById(‘main-humi‘)); option = { title: { text: ‘温度动态数据图‘ }, tooltip: { trigger: ‘axis’, axisPointer: { type: ‘cross’, label: { backgroundColor: ‘#283b56’ } } }, toolbox: { show: true, feature: { dataView: {readOnly: false}, restore: {}, saveAsImage: {} } }, dataZoom: { show: false, start: 0, end: 100 }, xAxis: [ { type: ‘category’, boundaryGap: true, data: (function (){ var now = new Date(); var res = []; var len = 10; while (len—) { res.unshift(now.toLocaleTimeString().replace(/^\D/,‘’)); now = new Date(now - 2000); } return res; })() }, { type: ‘category’, name: ‘时间‘, boundaryGap: true, data: (function (){ var res = []; var len = 10; while (len—) { res.push(len + 1); } return res; })() } ], yAxis: [ { type: ‘value’, scale: true, name: ‘温度(℃)’, max: 100, min: 0, boundaryGap: [0.2, 0.2] }, { type: ‘value’, scale: true, max: 100, min: 0, boundaryGap: [0.2, 0.2] }, ], series: [{ name:‘温度‘, type:‘line‘, xAxisIndex: 1, yAxisIndex: 1, data:(function (){ var res = []; var len = 10; while (len—) { res.push(0); } return res; })() } ] }; option2 = { title: { text: ‘湿度动态数据图‘ }, tooltip: { trigger: ‘axis’, axisPointer: { type: ‘cross’, label: { backgroundColor: ‘#283b56’ } } }, toolbox: { show: true, feature: { dataView: {readOnly: false}, restore: {}, saveAsImage: {} } }, dataZoom: { show: false, start: 0, end: 100 }, xAxis: [ { type: ‘category’, boundaryGap: true, data: (function (){ var now = new Date(); var res = []; var len = 10; while (len—) { res.unshift(now.toLocaleTimeString().replace(/^\D/,‘’)); now = new Date(now - 2000); } return res; })() }, { type: ‘category’, name: ‘时间‘, boundaryGap: true, data: (function (){ var res = []; var len = 10; while (len—) { res.push(len + 1); } return res; })() } ], yAxis: [ { type: ‘value’, scale: true, name: ‘湿度(%)’, max: 100, min: 0, boundaryGap: [0.2, 0.2] }, { type: ‘value’, scale: true, max: 100, min: 0, boundaryGap: [0.2, 0.2] }, ], series: [{ name:‘湿度‘, type:‘line‘, xAxisIndex: 1, yAxisIndex: 1, data:(function (){ var res = []; var len = 10; while (len—) { res.push(0); } return res; })() } ] }; client = new Paho.MQTT.Client(“www.liefyuan.top”, Number(9001), “websockets-test”);//建立客户端实例 client.connect({onSuccess:onConnect});//连接服务器并注册连接成功处理事件 function onConnect() { console.log(“onConnected“); topic = ‘v1/devices/me/telemetry’; client.subscribe(topic);//订阅主题 console.log(“subscribed”); //发送消息 } client.onConnectionLost = onConnectionLost;//注册连接断开处理事件 client.onMessageArrived = onMessageArrived;//注册消息接收处理事件 function onConnectionLost(responseObject) { if (responseObject.errorCode !== 0) { console.log(“onConnectionLost:”+responseObject.errorMessage); console.log(“连接已断开“); } } function onMessageArrived(message) { console.log(“收到消息:”+message.payloadString); console.log(“主题:“+message.destinationName); temprature = message.payloadString.slice(15,20); humidity = message.payloadString.slice(32,37); //console.log(temprature.slice(15,20)); //console.log(temprature.slice(32,37)); } count = 11; setInterval(function (){ axisData = (new Date()).toLocaleTimeString().replace(/^\D/,‘’); var data0 = option.series[0].data; // var data1 = option.series[1].data; var data3 = option2.series[0].data; // var data4 = option2.series[1].data; data0.shift(); data0.push(temprature); // data1.shift(); // data1.push(humidity); data3.shift(); data3.push(humidity); // data4.shift(); // data4.push(humidity); option.xAxis[0].data.shift(); option.xAxis[0].data.push(axisData); option.xAxis[1].data.shift(); option.xAxis[1].data.push(count++); option2.xAxis[0].data.shift(); option2.xAxis[0].data.push(axisData); option2.xAxis[1].data.shift(); option2.xAxis[1].data.push(count++); myChart.setOption(option); mychart2.setOption(option2); }, 2100); </script> </body> </html>