4. 云端指令下发至边缘

任务目标

本案例实现云端向边缘设备下发控制指令的完整闭环:在云平台(MQTT Broker)上发布一条JSON格式的控制指令,边缘设备(ESP8266/ESP32)订阅对应主题并接收指令,解析后驱动GPIO执行开关动作,同时回传执行状态确认。

环境与依赖

  • 硬件:ESP8266 或 ESP32 开发板(内置LED或外接LED至GPIO2)
  • Arduino IDE(安装ESP8266/ESP32开发板支持包)
  • 所需库:PubSubClient(MQTT客户端)、ArduinoJson(JSON解析)
  • MQTT Broker:可使用公共测试服务器 broker.emqx.io(端口1883)

实现方案

采用MQTT发布/订阅模型。云端作为发布者向主题 device/control 发送指令;边缘设备订阅该主题,收到消息后解析JSON中的 action 字段,执行对应GPIO操作,并向主题 device/status 发布执行结果。设备离线时云端无法感知,因此增加MQTT遗嘱消息(LWT)用于状态监控。

完整代码

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

// WiFi配置
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";

// MQTT配置
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
const char* client_id = "edge_device_001";
const char* topic_control = "device/control";
const char* topic_status = "device/status";

WiFiClient espClient;
PubSubClient client(espClient);

const int ledPin = 2;  // 板载LED

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

void publish_status(const char* action, bool success) {
  StaticJsonDocument<128> doc;
  doc["device_id"] = client_id;
  doc["action"] = action;
  doc["success"] = success;
  doc["timestamp"] = millis();
  char buffer[128];
  serializeJson(doc, buffer);
  client.publish(topic_status, buffer);
}

void callback(char* topic, byte* payload, unsigned int length) {
  // 解析JSON指令
  StaticJsonDocument<128> doc;
  deserializeJson(doc, payload, length);
  const char* action = doc["action"] | "";

  if (strcmp(action, "ON") == 0) {
    digitalWrite(ledPin, LOW);   // ESP8266低电平点亮
    publish_status("ON", true);
  } else if (strcmp(action, "OFF") == 0) {
    digitalWrite(ledPin, HIGH);
    publish_status("OFF", true);
  } else {
    publish_status(action, false);  // 未知指令
  }
}

void reconnect() {
  while (!client.connected()) {
    if (client.connect(client_id)) {
      client.subscribe(topic_control);
    }
  }
}

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);  // 初始关闭
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
  reconnect();
}

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

运行与验证

  1. 将代码中的 ssid 和 password 替换为实际WiFi信息,编译烧录至开发板。
  2. 打开串口监视器(波特率115200),确认设备成功连接WiFi和MQTT Broker。
  3. 使用MQTT客户端工具(如MQTT X、mosquitto_pub)向主题 device/control 发布指令:
mosquitto_pub -h broker.emqx.io -t device/control -m '{"action":"ON"}'
  1. 观察开发板板载LED应点亮;再发布 {"action":"OFF"},LED应熄灭。
  2. 订阅主题 device/status,应收到设备回传的状态确认消息,格式类似:
{"device_id":"edge_device_001","action":"ON","success":true,"timestamp":12345}

通过条件:LED状态随云端指令正确切换,且状态主题能收到对应的成功回执。若发布未知指令(如 {"action":"TOGGLE"}),状态主题应返回 "success":false,LED状态不变。

常见问题

  • 无法连接MQTT:确认WiFi已连接,且目标Broker允许匿名访问;公共Broker偶尔不稳定,可更换为 test.mosquitto.org。
  • 收不到指令:检查订阅主题是否与发布主题完全一致(区分大小写);确认设备在线(串口输出无报错)。
  • JSON解析失败:确保发布的消息是合法JSON格式,且字段名与代码中一致(action)。