4. QoS 1消息确认
任务目标
在ESP32与MQTT Broker之间使用QoS 1级别发布消息,验证Broker正确返回PUBACK确认,并理解QoS 1“至少一次投递”的语义。本案例聚焦发布端实现,订阅端仅作辅助验证。
环境与依赖
- 硬件:ESP32开发板(如ESP32-DevKitC)
- 软件:Arduino IDE(安装esp32核心)或ESP-IDF
- 库:PubSubClient 2.8+(Arduino环境下通过库管理器安装)
- Broker:本地或公网MQTT Broker(如mosquitto,broker.emqx.io:1883)
核心实现
PubSubClient库的publish()函数第三个参数即为QoS等级。当QoS=1时,库内部自动处理PUBACK等待与重发逻辑。以下代码实现:连接WiFi与Broker后,以QoS 1发布一条消息,并通过回调函数确认Broker已接收。
#include <WiFi.h>
#include <PubSubClient.h>
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
const char* topic = "esp32/qos1/test";
WiFiClient espClient;
PubSubClient client(espClient);
// 用于验证Broker是否收到消息的订阅主题
const char* ack_topic = "esp32/qos1/ack";
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("收到消息,主题: ");
Serial.println(topic);
Serial.print("内容: ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("连接WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi已连接");
}
void reconnect() {
while (!client.connected()) {
Serial.print("连接MQTT Broker...");
if (client.connect("ESP32_QoS1_Client")) {
Serial.println("已连接");
// 订阅确认主题,用于验证Broker确实收到了QoS 1消息
client.subscribe(ack_topic, 1);
} else {
Serial.print("连接失败,状态码=");
Serial.print(client.state());
Serial.println(" 5秒后重试");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
static unsigned long last_publish = 0;
if (millis() - last_publish > 10000) { // 每10秒发布一次
String msg = "QoS1消息 #" + String(millis() / 1000);
// 第三个参数1表示QoS级别为1
boolean result = client.publish(topic, msg.c_str(), 1);
if (result) {
Serial.print("QoS 1发布成功: ");
Serial.println(msg);
} else {
Serial.println("QoS 1发布失败");
}
last_publish = millis();
}
}
验证方法
- 将代码中的WiFi凭据替换为实际值,编译并烧录到ESP32。
- 打开串口监视器(波特率115200),观察日志:应看到“WiFi已连接”→“连接MQTT Broker...已连接”→“QoS 1发布成功: QoS1消息 #xxxx”。
- 使用MQTT客户端工具(如MQTT X、mosquitto_sub)订阅
esp32/qos1/test主题,确认能收到ESP32发布的消息。 - 在串口监视器中观察
收到消息,主题: esp32/qos1/ack——该消息由外部工具向esp32/qos1/ack主题发送,用于验证ESP32的订阅回调正常工作。
通过条件:外部MQTT客户端能持续收到来自ESP32的QoS 1消息(无重复或少量重复均可,取决于Broker实现),且ESP32串口输出“QoS 1发布成功”且无“发布失败”日志。若网络异常,PubSubClient会自动重发,这正是QoS 1“至少一次”的体现。
关键说明
- PubSubClient的
publish()返回true仅表示消息已进入发送流程并收到PUBACK(QoS 1),不代表Broker已转发给订阅者。 - QoS 1可能产生重复消息(Broker重发场景),订阅端需自行处理幂等性。
- 若需观察QoS 1与QoS 0的差异,可将代码中
publish()第三参数改为0,对比Broker端接收行为。