往期
《ESP8266通信指南》9-TCP通信(Arudino开发)-CSDN博客
《ESP8266通信指南》8-连接WIFI(Arduino开发)(非常简单)-CSDN博客
《ESP8266通信指南》7-Arduino 开发8266的环境配置与示例代码烧录-CSDN博客
《ESP8266通信指南》6-创建TCP服务器(AT指令)-CSDN博客
《ESP8266通信指南》5-TCP通信透传模式(AT指令)-CSDN博客
《ESP8266通信指南》4-以Client进行TCP通信(AT指令)-CSDN博客
《ESP8266通信指南》3-常用AT指令详解-8266连WIFI-CSDN博客
《ESP8266通信指南》2-ESP8266 AT测试-CSDN博客
《ESP8266通信指南》1-ESP8266 简介-CSDN博客
1. 小节目标
实现 ESP8266 的 MQTT 消息的传送,包括上报消息、接收消息并处理数据等功能。
2. 前言
在实现 ESP8266 进行 MQTT 传输之前,各位读者需要先完成环境搭建,WIFI 连接,也就是以下小节的内容:
《ESP8266通信指南》7-Arduino 开发8266的环境配置与示例代码烧录-CSDN博客
《ESP8266通信指南》8-连接WIFI(Arduino开发)(非常简单)-CSDN博客
3. MQTT 简单介绍
(图片来自于网络,侵权联系删除)
当我们谈到MQTT时,可以把它想象成一种特别聪明的通信方式,特别适合物联网这样的场景。想象一下,我们有很多设备,比如智能手机、传感器、智能家居设备,它们需要相互传递信息,但是我们希望这个过程既简单又高效。这时候MQTT就派上了用场。
我们可以将其想象成一种智能的通信方式,特别适合物联网这样的场景。在这个世界里,我们有三个关键角色:发布者、代理和订阅者。
3.1. 发布者
它们就像消息的发起者,生成并发布消息到一个特定的主题(topic),就像是发送一条短信或者邮件通知大家有什么事情要传达。
3.2. 代理
你可以把它想象成一个高效的邮递员,负责接收这些消息,并将它们发送给对这些消息感兴趣的订阅者。代理的作用就是确保消息能够顺利传递,就像是确保信件能够准确送达一样。
3.3. 订阅者
他们就像是等待接收消息的人,他们会在某个主题上订阅,然后就能够收到相关的消息,就像是收到一封信件或者通知一样。
MQTT的优势在于它的简单和高效。它的消息传输速度很快,协议本身也非常简洁,适合在网络带宽有限的情况下使用,比如移动网络或者电池供电的设备。此外,它还可以根据需要提供不同级别的消息传输可靠性,让我们可以根据具体情况选择适合的方案。
4. MQTT 相关包安装
在进行 MQTT 通信之前,需要安装相关的库,PubSubClient
,在下图,我已经安装完成,没有安装的读者需要自行安装。
5. MQTT 客户端 MQTTX 安装和使用
5.1. 下载 MQTTX 和安装
官网下载地址:MQTTX:全功能 MQTT 客户端工具
点击这里就可以下载安装了,安装过程非常简单,一直下一步就可以了,这里就不演示了。
5.2. 设置为中文
5.3. 创建一个 MQTT 连接
- 点击左侧的“+”号
- 输入任意字符的名称,这里的名称只是为了方便我们管理
- 点击右上角的“连接”按钮
5.4. 订阅主题
订阅主题分为以下步骤
- 点击“添加订阅”
- 输入主题的名称
- 点击订阅
- 演示中订阅的主题是
“/ct/iot”
,读者可以自己自定义主题
5.4.1. 发布消息
发布消息分为以下步骤:
- 输入主题名称
- 输入消息
- 点击发送
因为我们订阅了主题“/ct/iot”
,所以我们往主题“/ct/iot”
发布的时候,自己也能收到,也就是上图的效果。
6. 进入正题
6.1. 开启移动热点
按照之前章节,在电脑上打开一个移动热点,账号密码自定义,博主的是设置为以下:
- 账号:ct-iot
- 密码:111222333
6.2. 完整代码
按照惯例,先上代码,代码的功能是每隔 5 秒钟上报一个数据,到主题(代码中是“/ct/iot/ct_topic”,可以更改为任意内容),在接收到该主题来的数据的时候,会立马打印出来。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* ssid = "ct-iot"; // Wi-Fi账号
const char* password = "111222333"; // Wi-Fi密码
const char* mqtt_server = "broker.emqx.io"; // MQTT服务器地址
const char* topic = "/ct/iot/ct_topic"; // MQTT主题
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
char clientId[10]; // 用于存储生成的随机ID
// 设置Wi-Fi连接
void setup_wifi() {
delay(10);
// 连接到Wi-Fi网络
Serial.println();
Serial.print("正在连接到 ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("Wi-Fi连接成功");
Serial.println("IP地址: ");
Serial.println(WiFi.localIP());
}
// 接收到MQTT消息时的回调函数
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("收到消息 [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
// 重新连接到MQTT服务器
void reconnect() {
// 循环直到重新连接到MQTT
while (!client.connected()) {
Serial.print("尝试连接到MQTT服务器...");
// 尝试连接
if (client.connect(clientId)) { // 使用生成的随机ID作为客户端ID
Serial.println("连接成功");
// 连接成功后订阅我们感兴趣的主题
client.subscribe(topic);
} else {
Serial.print("连接失败, rc=");
Serial.print(client.state());
Serial.println(" 5秒后重试");
// 等待5秒后重试
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
// 生成随机ID
randomSeed(analogRead(0)); // 使用模拟引脚0的读数作为随机数种子
for (int i = 0; i < 9; ++i) {
clientId[i] = random(33, 126); // 生成ASCII码为33到126之间的随机数
}
clientId[9] = '\0'; // 添加字符串结束符
}
void loop() {
// 如果需要,重新连接
if (!client.connected()) {
reconnect();
}
// 确保客户端已连接到MQTT服务器
client.loop();
// 每隔5秒发布一次数据
long now = millis();
if (now - lastMsg > 5000) {
lastMsg = now;
++value;
snprintf (msg, 50, "Hello, World! #%ld", value);
Serial.print("发布消息: ");
Serial.println(msg);
// 将消息发布到指定主题
client.publish(topic, msg);
}
}
需要各位读者更改的位置:
- 移动热点的名称:ssid
- 移动热点的密码:password
- 如果你也是用 MQTTX,他们是提供一个免费的 MQTT 服务器服务,也就是我代码中写的这个
mqtt_server = "broker.emqx.io"
,读者就不需要更改 - 主题
topic
,建议各位读者在主题里面加入自己的名字或者随机的内容,因为我们是用公共服务器,如果主题跟别人一样的话,会接收到其他数据,这样就不好啦,也有可能导致我们数据泄露~~
6.3. 代码效果
6.3.1. ESP8266 上报数据
我们可以看到,ESP8266 每隔 5 秒钟就会上发一次数据给 MQTT 服务器,MQTTX 客户端接收到就会打印出来。
6.3.2. ESP8266 接收数据
如下图,我们在 MQTTX上发送数据(往 ESP8266 订阅的主题上),ESP8266 就可以接收到接着打印出来。
7. 代码详解
7.1. 包含必要的库文件
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
这里引入了ESP8266WiFi.h
和PubSubClient.h
两个库文件,分别用于ESP8266的Wi-Fi连接和MQTT通信。
7.2. 设置 Wi-Fi 和 MQTT 相关信息
const char* ssid = "ct-iot"; // Wi-Fi账号
const char* password = "111222333"; // Wi-Fi密码
const char* mqtt_server = "broker.emqx.io"; // MQTT服务器地址
const char* topic = "/ct/iot/ct_topic"; // MQTT主题
这里定义了Wi-Fi的账号和密码,以及MQTT服务器的地址和要订阅/发布的主题。
7.3. 全局变量和对象声明
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
char clientId[10]; // 用于存储生成的随机ID
声明了一个WiFiClient
类型的espClient
对象和一个PubSubClient
类型的client
对象,用于处理Wi-Fi连接和MQTT通信。同时定义了一些全局变量,包括最后一次发送消息的时间、消息内容、计数器和客户端ID。
7.3.1. 设置 Wi-Fi 连接函数
void setup_wifi() {
// 等待一会儿
delay(10);
// 连接到Wi-Fi网络
Serial.println();
Serial.print("正在连接到 ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("Wi-Fi连接成功");
Serial.println("IP地址: ");
Serial.println(WiFi.localIP());
}
该函数用于连接到Wi-Fi网络,并在连接成功后输出本地IP地址。
7.3.2. 设置 MQTT 回调函数
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("收到消息 [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
这个回调函数用于处理接收到的MQTT消息,将收到的消息打印到串行监视器中。
7.3.3. 重新连接到 MQTT 服务器函数
void reconnect() {
while (!client.connected()) {
Serial.print("尝试连接到MQTT服务器...");
if (client.connect(clientId)) { // 使用生成的随机ID作为客户端ID
Serial.println("连接成功");
client.subscribe(topic); // 订阅指定主题
} else {
Serial.print("连接失败, rc=");
Serial.print(client.state());
Serial.println(" 5秒后重试");
delay(5000); // 5秒后重试
}
}
}
这个函数用于重新连接到MQTT服务器,并在连接成功后订阅指定的主题。
7.3.4. setup() 函数
void setup() {
Serial.begin(115200);
setup_wifi(); // 设置Wi-Fi连接
client.setServer(mqtt_server, 1883); // 设置MQTT服务器
client.setCallback(callback); // 设置回调函数
// 生成随机ID
randomSeed(analogRead(0)); // 使用模拟引脚0的读数作为随机数种子
for (int i = 0; i < 9; ++i) {
clientId[i] = random(33, 126); // 生成ASCII码为33到126之间的随机数
}
clientId[9] = '\0'; // 添加字符串结束符
}
在setup()
函数中,初始化串行通信,设置Wi-Fi连接,设置MQTT服务器,设置回调函数,并生成随机的客户端ID。
7.3.5. 主循环
void loop() {
if (!client.connected()) {
reconnect(); // 如果需要,重新连接到MQTT服务器
}
client.loop(); // 确保客户端已连接到MQTT服务器
// 每隔5秒发布一次数据
long now = millis();
if (now - lastMsg > 5000) {
lastMsg = now;
++value;
snprintf (msg, 50, "Hello, World! #%ld", value);
Serial.print("发布消息: ");
Serial.println(msg);
client.publish(topic, msg); // 发布消息到指定主题
}
}
在主循环中,检查MQTT客户端是否连接到服务器,如果未连接,则调用重新连接函数。然后,确保客户端已连接到MQTT服务器,并通过client.loop()
函数处理MQTT消息。最后,每隔5秒发布一条带有计数器的消息到指定主题。
通过以上步骤,我们实现了一个能够通过Wi-Fi和MQTT与远程服务器通信的ESP8266应用程序。
8. 结语
介绍了 ESP8266 使用 MQTT 相关的包和客户端模拟器 MQTTX,接着编写代码,完成以下功能:
- 设置Wi-Fi连接,连接到指定的Wi-Fi网络后输出IP地址
- 设置MQTT客户端,并生成一个随机的客户端ID
- 在主循环中,持续尝试连接到MQTT服务器,如果连接成功则订阅指定的主题
- 定时发布一条消息到MQTT服务器
- 在串行监视器中输出接收到的消息
柴头物联网出品