ESP系列入门教程(三)——之MQTT通信实现数据上报【分别附上 ESP32 + ESP8266 的具体代码】

发布时间:2024年01月16日

概要

最近在跟着几个大佬的教学视频做项目。陆续会更新记录一些要点,便于后期总结笔记的时候进行引用。
也可以帮助有心跟着一起复刻的宝子们,更好地捋清思路。

【本系列教程 - 总目标】:
使用ESP系列板卡,通过MQTT进行数据通信,达到远程控制多个传感器的效果。

ESP芯片官方技术文档链接
https://www.espressif.com.cn/zh-hans/support/documents/technical-documents

◆配置说明
硬件板卡:ESP系列板卡 <本系列教程以ESP32ESP8266为例>

硬件元件:

  • DHT11温湿度传感器
  • 一颗LED灯
  • 一个5v驱动的继电器
  • 一个按键开关
  • 杜邦线若干

◆需求概述

【本篇章目标】
ESP系列入门教程(一) 中,我们已经完成了ESP系列驱动继电器,通过按键达到控制LED亮灭的效果

ESP系列入门教程(二)中,我们进一步完成了DHT11温湿度传感器驱动控制

本章,我们将基于之前的代码,继续进行开发,完成MQTT通信的实现,这也是本系列教程的重点之一,宝子们最好实操一下哦,期待大家的结果反馈~

同时附上代码(ESP32和ESP8266代码),希望对宝子们有所帮助。

技术名词简介

● ESP系列简介

ESP芯片是一种由乐鑫科技(Espressif Systems)开发的低功耗无线通信芯片。

ESP芯片系列包括ESP8266和ESP32两个主要型号。这些芯片具有强大的处理能力和丰富的外设接口,适用于物联网(IoT)应用和嵌入式系统开发。

◆ESP8266
是一款高度集成的Wi-Fi芯片,具有低功耗和低成本的特点。它支持TCP/IP协议栈,可以通过Wi-Fi连接到互联网,并与其他设备进行通信。ESP8266可以作为主控芯片,与传感器、执行器等设备进行通信,实现智能家居、智能农业、智能工业等应用。

◆ESP32
是ESP8266的升级版本,除了具备Wi-Fi功能外,还增加了蓝牙(Bluetooth)功能。ESP32具有更高的处理能力和更多的外设接口,支持更复杂的应用场景。它可以作为Wi-Fi和蓝牙网关,连接多个设备并实现数据传输和控制。

ESP芯片具有开放的开发环境和丰富的开发资源,开发者可以使用Arduino IDE、MicroPython等开发工具进行编程。此外,乐鑫科技还提供了丰富的文档和示例代码,方便开发者快速上手和开发应用。

● MQTT简介

MQTT是一种轻量级的消息传输协议,用于在低带宽和不稳定的网络环境中传输小型数据包。
设计宗旨和目标:简单、轻量级和易于实现
因此使其成为物联网应用中常用的通信协议之一

MQTT协议基于发布/订阅模式,这使得消息的传输变得高效和灵活,可以实现一对多的通信。
通信实现的过程中有两个主要角色:发布者和订阅者。

  • 发布者(pub):负责将消息发布到特定的主题(Topic)。
  • 订阅者(sub):用来订阅感兴趣的主题,以接收相关的消息。

MQTT协议具有以下特点:

轻量级:MQTT协议的设计非常简单,消息头部信息很小,使得它在网络带宽有限的情况下能够高效传输。
可靠性:MQTT协议支持三种消息传输质量等级:至多一次(At most once)、至少一次(At least once)和刚好一次(Exactly once),可以根据应用需求选择适当的等级。
异步通信:MQTT协议支持异步通信,发布者和订阅者之间的通信不需要实时连接,可以通过消息队列进行中转。
低功耗:MQTT协议适用于低功耗设备,可以在资源受限的设备上运行,如传感器、嵌入式设备等。

● MQTTX工具简介

MQTTX是一个开源的MQTT客户端工具,用于测试和调试MQTT协议。
它提供了一个直观的用户界面,可以方便地连接到MQTT代理,并进行发布和订阅消息的操作。

MQTTX支持多个MQTT代理的管理,并且可以保存和加载连接配置。
此外,MQTTX还提供了一些高级功能,如消息记录、消息过滤、消息计数等,以帮助用户更好地理解和分析MQTT通信。

通过MQTTX,用户可以轻松地测试和调试MQTT应用程序,以确保其正常运行。

硬件连接实现(同教程2,没有变化)

ESP8266和ESP32引脚图有很多部分不一样,详情请参考前面写好的:ESP系列入门教程(一)
https://blog.csdn.net/qq_38141255/article/details/135597139?spm=1001.2014.3001.5501
里面有详细的引脚图,有需要请对照配置。

以ESP32图示为例:
图来自B站大佬:莽小石
在这里插入图片描述

代码实现

代码前说明,对于MQTT通信功能,ESP32和ESP8266,在实际操作的过程中,开始逐步出现了略微的不同。
具体缘由,期望大佬可以留言给大家讲讲。(*?▽?*)大佬我们做朋友好不好

我先直接分享一下我实际调试过程中的代码。
ESP32和ESP8266是分开的,宝子们在调测的时候,注意对照入座。

●Demo:按键开关灯,并通过MQTT将信息上报

PS:由于两块板子是分开调测的,所以在代码实现上可能会有略微的不同,但逻辑是一样的。

实验描述
代码刷入后,ESP板卡上电后,自动连接wifi,若wifi连接成功后。MQTT将会自动连接和订阅MQTT_Topic(可自定义,但要和MQTT服务器订阅发布的topic一致)。

  • MQTT数据上报:通过按键开关灯时,MQTT服务器将会受到ESP板卡发布的开关灯状态数据。

PS:WiFi连接信息 和 MQTT连接信息 需要重新填写,根据自己测试环境填写真实数据。

○ ESP8266代码
#include <Arduino.h>
#include <WiFiClient.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>

// WiFi连接信息
#define WIFI_SSID "AA"
#define WIFI_PASS "12345678"
// MQTT服务器信息
#define MQTT_HOST "你的MQTT服务器IP"
#define MQTT_PORT 1883
#define MQTT_CLIENT_ID "My_Device"
#define MQTT_USER "你的MQTT服务器用户名"
#define MQTT_PASS "你的MQTT服务器密码"

#define MQTT_Topic "test_ESP8266" 
#define LED_On     "LED_On"
#define LED_Off    "LED_Off"

// 创建WiFi客户端和MQTT客户端实例
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
Ticker ticker;

// 定义按键和继电器的引脚
const int buttonPin = 2;   // 按键连接到引脚2
const int relayPin  = 4;    // 继电器连接到引脚4

int buttonState = 0;       // 保存当前按键状态(低电平或高电平)
int lastButtonState = 0;   // 保存上一次的按键状态
unsigned long lastDebounceTime  = 0;     // 上次去抖动的时间
unsigned long debounceDelay     = 120;   // 去抖动延迟时间,单位:毫秒

void connectWIFI() {
  // 连接WIFI热点
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  int retryCount = 1;
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("正在连接WiFi...");
    delay(3000);
  }
  Serial.println("WIFI连接成功");
  Serial.println("IP地址: " + WiFi.localIP().toString());
}

// 设置MQTT连接函数
void setupMQTT() {
  // 配置MQTT服务器
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  // 设置回调函数
  mqttClient.setCallback(recvMsg);
}

void sendMsg(int status) {
  if (mqttClient.connected()) {
    String topic = MQTT_Topic;
    String payload = "";
    if(status==1)
    {
          payload = LED_On;
    }
    else{
          payload = LED_Off;
    }

    if (mqttClient.publish(topic.c_str(), payload.c_str())) {
    // if (mqttClient.publish(topic.c_str(), payload.c_str())) {
      Serial.println("MQTT消息发送成功");
    } else {
      Serial.println("MQTT消息发送失败");
    }
  } else {
    Serial.println("MQTT服务器未连接");
  }
}
 
void recvMsg(char *topic, uint8_t *payload, size_t length) {
  Serial.println("topic: " + String(topic));
  Serial.println("payload: " + String((char *)payload).substring(0, length) + "length: " + String(length));
}
 
void connectMQTT() {
  if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS)) {
    Serial.println("MQTT服务器连接成功");
    String topic = MQTT_Topic;
    if (mqttClient.subscribe(topic.c_str())) {
      Serial.println("MQTT主题订阅成功");
    } else {
      Serial.println("MQTT主题订阅失败");
    }
    // ticker.attach(3, sendMsg);
  } else {
    Serial.println("MQTT服务器连接失败");
    ticker.detach();
    delay(3000);
  }
}

// 初始化函数
void setup() {
  // put your setup code here, to run once:

  // 设置波特率
  Serial.begin(115200);

  //设置灯引脚
  pinMode(buttonPin, INPUT);
  pinMode(relayPin , OUTPUT);

  // 连接WIFI热点
  connectWIFI();

  // 配置MQTT服务器
  setupMQTT();
  // 连接MQTT服务器
  connectMQTT();
} 

void loop() {
  // put your main code here, to run repeatedly:
 
  // 检查MQTT连接是否成功,如果未连接则尝试重新连接
  if (mqttClient.connected()) {
    mqttClient.loop();
  } else {
    connectMQTT();
  }

  // 读取按键状态
  int reading = digitalRead(buttonPin);

  // 检测按键状态变化并进行防抖处理
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;

      // 检测按键是否被按下,执行相应的操作
      if (buttonState == HIGH) {
        // 检测继电器状态并切换
        if (digitalRead(relayPin) == HIGH) {
          digitalWrite(relayPin, LOW);
          Serial.println("Relay OFF");
          // 发布关灯的主题和内容到MQTT
          mqttClient.publish("test_ESP8266", "LED_Off");
          mqttClient.endPublish();
        } else {
          digitalWrite(relayPin, HIGH);
          Serial.println("Relay ON");
          // 发布开灯的主题和内容到MQTT
          mqttClient.publish("test_ESP8266", "LED_On");
          mqttClient.endPublish();
        }
      }
    }
  }
  // 保存当前按键状态,以便下一次比较
  lastButtonState = reading;
}

○ ESP32代码
#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>

// WiFi连接信息
const char* ssid = "AA";
const char* password = "12345678";

// MQTT服务器信息
const char* mqttServer = "你的MQTT服务器IP";
const int mqttPort = 1883;
const char* mqttUsername = "你的MQTT服务器用户名";
const char* mqttPassword = "你的MQTT服务器密码";

// 创建WiFi客户端和MQTT客户端实例
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);

// 设置WiFi连接函数
void setupWiFi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("正在连接WiFi...");
  }
  Serial.println("已连接到WiFi");
}

// 设置MQTT连接函数
void setupMQTT() {
  mqttClient.setServer(mqttServer, mqttPort);
}

// 重新连接MQTT服务器函数
void reconnectMQTT() {
  while (!mqttClient.connected()) {
    Serial.println("正在连接到MQTT...");
    if (mqttClient.connect("ESP32Client", mqttUsername, mqttPassword)) {
      Serial.println("连接到MQTT");
    } else {
      Serial.print("MQTT连接失败,rc=");
      Serial.print(mqttClient.state());
      Serial.println(" 5秒钟后重试...");
      delay(5000);
    }
  }
}

// 定义按键和继电器的引脚
const int buttonPin = 2;   // 按键连接到引脚2
const int relayPin = 4;    // 继电器连接到引脚4

int buttonState = 0;       // 保存当前按键状态(低电平或高电平)
int lastButtonState = 0;   // 保存上一次的按键状态
unsigned long lastDebounceTime = 0;  // 上次去抖动的时间
unsigned long debounceDelay = 120;    // 去抖动延迟时间,单位:毫秒

// 初始化函数
void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT);
  pinMode(relayPin, OUTPUT);
  setupWiFi();
  setupMQTT();
}

// 主循环函数
void loop() {
  // 检查MQTT连接状态,如果未连接则尝试重新连接
  if (!mqttClient.connected()) {
    reconnectMQTT();
  }
  // 处理MQTT消息
  mqttClient.loop();

  // 读取按键状态
  int reading = digitalRead(buttonPin);

  // 检测按键状态变化并进行防抖处理
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;

      // 检测按键是否被按下,执行相应的操作
      if (buttonState == HIGH) {
        // 检测继电器状态并切换
        if (digitalRead(relayPin) == HIGH) {
          digitalWrite(relayPin, LOW);
          Serial.println("Relay OFF");
          // 发布关灯的主题和内容到MQTT
          mqttClient.publish("kaiguan", "guan");
        } else {
          digitalWrite(relayPin, HIGH);
          Serial.println("Relay ON");
          // 发布开灯的主题和内容到MQTT
          mqttClient.publish("kaiguan", "kai");
        }
      }
    }
  }

  // 保存当前按键状态,以便下一次比较
  lastButtonState = reading;
}

文章来源:https://blog.csdn.net/qq_38141255/article/details/135616566
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。