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

基于Arduino的MQTT多设备序列执行问题求助

WeMos D1 Mini MQTT多设备链式通信解决方案

核心问题定位

你遇到的多设备仅最后一个响应的问题,90%概率是MQTT客户端ID重复导致的:MQTT Broker会强制踢掉使用相同客户端ID的旧连接,只有最后上线的设备能保持在线。其次是主题设计不合理,所有设备订阅同一主题,导致指令无法精准投递。

实现方案

1. MQTT主题与客户端ID规范

  • 客户端ID:每个设备必须使用唯一ID,格式建议为wemos_<id_dev>(比如wemos_001),避免Broker踢掉重复连接
  • 主题分层设计:
    • 设备指令主题:device/command/<id_dev> → 每个设备仅订阅自己ID对应的指令主题
    • 设备日志主题:device/log/<id_dev> → 设备完成任务后向该主题发送日志
    • 设备触发主题:device/trigger/<id_dev> → 用于设备间链式触发(如001完成后向device/trigger/002发消息)

2. 设备逻辑调整

所有设备共用同一代码,仅需修改id_dev(当前设备ID)和next_dev(下一个待触发设备ID,最后一个设备设为空字符串):

  • 启动时:连接MQTT Broker,订阅自己的指令、触发主题
  • 收到指令/触发消息时:执行任务 → 发送完成日志 → 触发下一个设备(如果存在)
  • 电脑端:发送启动指令到device/command/001,订阅device/log/#接收所有日志,收到003的日志后判定序列结束

3. 修正后的代码示例

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PWD";
const char* mqtt_server = "YOUR_MQTT_BROKER_IP";

// 每个设备修改这两个参数
const char* id_dev = "001";       // 当前设备ID
const char* next_dev = "002";     // 下一个设备ID,最后一个设备设为""

WiFiClient espClient;
PubSubClient client(espClient);
char clientId[20];

void setup() {
  Serial.begin(115200);
  snprintf(clientId, sizeof(clientId), "wemos_%s", id_dev); // 生成唯一客户端ID
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  reconnect();
}

void setup_wifi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  // 执行任务(替换为你的实际业务代码)
  Serial.print("Device ");
  Serial.print(id_dev);
  Serial.println(" executing task...");
  execute_task();

  // 发送完成日志到电脑
  char log_topic[30];
  snprintf(log_topic, sizeof(log_topic), "device/log/%s", id_dev);
  char log_msg[50];
  snprintf(log_msg, sizeof(log_msg), "Device %s task completed", id_dev);
  client.publish(log_topic, log_msg);

  // 触发下一个设备
  if (strlen(next_dev) > 0) {
    char trigger_topic[30];
    snprintf(trigger_topic, sizeof(trigger_topic), "device/trigger/%s", next_dev);
    client.publish(trigger_topic, "start");
    Serial.print("Triggered device ");
    Serial.println(next_dev);
  } else {
    // 最后一个设备,发送序列结束通知
    client.publish("device/log/sequence", "All tasks completed");
  }
}

// 模拟任务执行,替换为你的实际代码
void execute_task() {
  delay(2000); // 模拟任务耗时
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

// 重连逻辑,自动重新订阅主题
void reconnect() {
  while (!client.connected()) {
    if (client.connect(clientId)) {
      char cmd_topic[30];
      snprintf(cmd_topic, sizeof(cmd_topic), "device/command/%s", id_dev);
      char trigger_topic[30];
      snprintf(trigger_topic, sizeof(trigger_topic), "device/trigger/%s", id_dev);
      client.subscribe(cmd_topic);
      client.subscribe(trigger_topic);
      Serial.print("Device ");
      Serial.print(id_dev);
      Serial.println(" connected to MQTT");
    } else {
      Serial.print("Reconnect failed, retrying in 5s...");
      delay(5000);
    }
  }
}

4. 测试与验证步骤

  1. 分别给3个设备烧录代码,对应修改id_dev和next_dev:
    • 设备001:id_dev="001",next_dev="002"
    • 设备002:id_dev="002",next_dev="003"
    • 设备003:id_dev="003",next_dev=""
  2. 启动MQTT Broker(如Mosquitto),确保Broker允许多客户端连接
  3. 使用MQTT客户端工具(如MQTTX)发送消息start到device/command/001
  4. 观察各设备串口输出,同时监控device/log/#主题消息,确认序列按001→002→003执行,最后收到序列结束通知

内容的提问来源于stack exchange,提问作者mir_kol

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 20:48:45