You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:50:06