Arduino--ESP8266--ESP-01学习笔记--连接WiFi、连接MQTT服务器、web显示

25 篇文章 21 订阅

无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家。教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点这里可以跳转到教程。


前言

做这个东西之前需要知道的事

 这个东西是通过使用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>
    <!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
    <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>


评论 79
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值