ESP8266的MQTT发布订阅代码合并方法求助
解决ESP8266同时作为MQTT发布者和订阅者的代码合并问题
嘿,我完全懂你现在的处境——两段代码单独跑都好好的,合在一起就失效了,这种情况在刚接触ESP8266和MQTT的时候太常见啦!别慌,我来帮你把两段代码合并好,同时给你讲清楚关键的注意点,避免以后再踩同样的坑。
首先先说说合并时必须注意的几个核心问题:
- 统一配置信息:你原来的两段代码里MQTT服务器地址不一样(发布者是
192.168.71.107,订阅者是192.168.71.127),clientID也都是ESP01,这会导致连接冲突,必须统一或者调整 - 保留MQTT回调函数:订阅功能依赖
setCallback设置的消息处理函数,合并后不能丢 - loop里必须调用
client.loop():这是MQTT客户端处理订阅消息、保持连接的关键,发布者代码原来的loop里没有这个,合并后一定要加上 - 整合重连逻辑:不管是发布还是订阅,一旦MQTT连接断开,都要自动重连,并且重新订阅主题
接下来是合并并优化后的完整代码,我已经帮你修正了不一致的配置,整合了所有功能:
#include <Bounce2.h> #include <ESP8266WiFi.h> #include <PubSubClient.h> // ------------------- 硬件引脚定义 ------------------- const int pubLedPin = 0; // 发布者用的LED(按钮按下时亮) const int subLedPin = 16; // 订阅者用的LED(收到消息时控制) const int buttonPin = 13; // 触发发布的按钮引脚 // ------------------- WiFi配置 ------------------- const char* ssid = "TP-LINK_7224"; const char* wifi_password = "RFID7890"; // ------------------- MQTT配置 ------------------- const char* mqtt_server = "192.168.71.107"; // 统一成一个MQTT服务器地址,根据你的实际情况修改 const char* mqtt_pub_topic = "Flash_Message"; // 发布主题 const char* mqtt_sub_topic = "flash"; // 订阅主题 const char* mqtt_username = "pi"; const char* mqtt_password = "pi123"; const char* clientID = "ESP01_PubSub"; // 修改成唯一的客户端ID,避免冲突 // ------------------- 对象初始化 ------------------- Bounce bouncer = Bounce(); WiFiClient wifiClient; PubSubClient client(mqtt_server, 1883, wifiClient); // ------------------- MQTT消息回调函数(处理订阅到的消息) ------------------- void ReceivedMessage(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(); // 处理消息逻辑,保留你原来的订阅者逻辑 if (length >=5 && (char)payload[0] == 'E' && (char)payload[1] == 'S' && (char)payload[2] == 'P' && (char)payload[3] == '0' && (char)payload[4] == '1' ) { digitalWrite(subLedPin, HIGH); delay(4000); digitalWrite(subLedPin, LOW); } if ((char)payload[0] == '0') { digitalWrite(subLedPin, LOW); delay(1000); } } // ------------------- MQTT连接函数(包含订阅主题) ------------------- bool connectToMqtt() { // 连接MQTT服务器,同时设置用户名密码 if (client.connect(clientID, mqtt_username, mqtt_password)) { Serial.println("成功连接到MQTT服务器!"); // 连接成功后订阅主题 client.subscribe(mqtt_sub_topic); Serial.print("已订阅主题: "); Serial.println(mqtt_sub_topic); return true; } else { Serial.print("MQTT连接失败,错误代码: "); Serial.println(client.state()); return false; } } void setup() { // 初始化引脚模式 pinMode(pubLedPin, OUTPUT); pinMode(subLedPin, OUTPUT); pinMode(buttonPin, INPUT); // 初始状态关闭LED digitalWrite(pubLedPin, HIGH); digitalWrite(subLedPin, LOW); // 初始化按钮防抖 bouncer.attach(buttonPin); bouncer.interval(5); // 初始化串口 Serial.begin(115200); Serial.println("启动中..."); // 连接WiFi Serial.print("连接WiFi: "); Serial.println(ssid); WiFi.begin(ssid, wifi_password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi连接成功!"); Serial.print("IP地址: "); Serial.println(WiFi.localIP()); // 设置MQTT消息回调函数 client.setCallback(ReceivedMessage); // 连接MQTT服务器 connectToMqtt(); } void loop() { // 1. 处理按钮防抖更新 bouncer.update(); // 2. 检查按钮状态,处理发布逻辑 if (bouncer.rose()) { // 按钮按下,点亮发布用LED digitalWrite(pubLedPin, LOW); Serial.println("按钮被按下,准备发布消息..."); // 先检查MQTT连接状态,如果断开先重连 if (!client.connected()) { if (connectToMqtt()) { Serial.println("重连MQTT成功,继续发布消息"); } else { Serial.println("重连MQTT失败,无法发布消息"); digitalWrite(pubLedPin, HIGH); delay(1000); return; } } // 发布消息到指定主题 if (client.publish(mqtt_pub_topic, "Button pressed!")) { Serial.println("消息发布成功!"); } else { Serial.println("消息发布失败,尝试重连后再次发布"); connectToMqtt(); delay(10); client.publish(mqtt_pub_topic, "Button pressed!"); } } else if (bouncer.fell()) { // 按钮松开,关闭发布用LED digitalWrite(pubLedPin, HIGH); } // 3. 检查MQTT连接状态,断开则重连 if (!client.connected()) { // 每隔2秒尝试重连一次,避免频繁重试 static unsigned long lastReconnectAttempt = 0; if (millis() - lastReconnectAttempt > 2000) { lastReconnectAttempt = millis(); connectToMqtt(); } } // 4. 必须调用这个函数,让MQTT客户端处理订阅消息、保持心跳等 client.loop(); }
代码关键优化点说明
- 统一配置:把原来两段代码里的WiFi、MQTT配置整合到一起,修正了不一致的MQTT服务器地址,修改了clientID避免连接冲突
- 分离硬件引脚:把发布和订阅用的LED引脚分开定义,避免混淆
- 完善重连逻辑:在loop里定期检查MQTT连接,断开时自动重连,并且添加了重试间隔,避免频繁占用资源
- 整合发布和订阅逻辑:在loop里先处理按钮发布,再检查连接,最后调用
client.loop()处理订阅消息,确保两边功能都正常工作 - 增强调试信息:添加了更多串口输出,方便你排查问题
额外注意事项
- 确保你的MQTT服务器地址是正确的,并且服务器允许这个clientID连接
- 按钮接线要正确,注意上拉下拉(代码里用的是INPUT模式,如果按钮是接GND的话,可能需要改成INPUT_PULLUP,根据你的实际接线调整)
- 上传代码前,记得在Arduino IDE里选择正确的ESP8266开发板和端口
内容的提问来源于stack exchange,提问作者Tahreem Khan
相关产品推荐
相关产品推荐

