2. 发布/订阅基础
任务目标
本案例实现ESP32通过MQTT协议同时发布和订阅多个主题:设备向esp32/status周期发布在线状态,同时订阅esp32/led和esp32/msg两个主题,分别用于控制板载LED和接收文本消息,演示消息的实时双向收发。
环境与依赖
- 硬件:ESP32开发板(板载LED通常接GPIO2)
- 软件:Arduino IDE(安装esp32开发板包)
- MQTT Broker:本机运行Mosquitto,或使用公共Broker(如broker.emqx.io:1883)
- 库:PubSubClient(Arduino库管理器搜索安装)
关键完整代码
#include <WiFi.h>
#include <PubSubClient.h>
// WiFi配置
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
// MQTT Broker配置
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
const char* client_id = "esp32-client-001";
// 主题定义
const char* pub_topic = "esp32/status";
const char* sub_topic_led = "esp32/led";
const char* sub_topic_msg = "esp32/msg";
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastPublishTime = 0;
const long publishInterval = 5000; // 5秒发布一次
void setup_wifi() {
delay(10);
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String message;
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// 根据主题处理消息
if (strcmp(topic, sub_topic_led) == 0) {
if (message == "on") {
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("LED ON");
} else if (message == "off") {
digitalWrite(LED_BUILTIN, LOW);
Serial.println("LED OFF");
}
} else if (strcmp(topic, sub_topic_msg) == 0) {
Serial.print("Received message: ");
Serial.println(message);
}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(client_id)) {
Serial.println("connected");
// 连接成功后订阅主题
client.subscribe(sub_topic_led);
client.subscribe(sub_topic_msg);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// 周期发布状态
if (millis() - lastPublishTime > publishInterval) {
String status = "online";
client.publish(pub_topic, status.c_str());
Serial.println("Published: " + status);
lastPublishTime = millis();
}
}
运行与验证
- 将代码中的
ssid和password替换为实际WiFi信息。 - 编译并烧录到ESP32开发板,打开串口监视器(波特率115200)。
- 观察串口输出:WiFi连接成功后,显示“Attempting MQTT connection...connected”,说明MQTT连接成功。
- 每5秒串口输出“Published: online”,说明发布功能正常。
验证订阅功能:使用MQTT客户端工具(如MQTTX或mosquitto_pub)向Broker发送消息:
# 控制LED(在终端执行)
mosquitto_pub -h broker.emqx.io -t "esp32/led" -m "on"
mosquitto_pub -h broker.emqx.io -t "esp32/led" -m "off"
# 发送文本消息
mosquitto_pub -h broker.emqx.io -t "esp32/msg" -m "Hello ESP32"
通过条件:
- 发送
on/off到esp32/led时,板载LED相应点亮/熄灭,串口输出“LED ON”/“LED OFF”。 - 发送任意文本到
esp32/msg时,串口输出“Received message: 对应内容”。 - 串口持续每5秒显示“Published: online”,且无断连重连日志。
常见问题
- 连接失败(rc=-2):网络不通或Broker地址错误,检查WiFi连接和Broker地址。
- 收不到消息:确认订阅主题与发布主题完全一致(区分大小写),且已在
reconnect()中完成订阅。 - LED不动作:确认开发板LED引脚定义,部分开发板LED_BUILTIN可能为GPIO2或GPIO16,按实际硬件调整。