物联网控制的智能LED灯带(2):MQTT网关(WS2812/2811,ESP32,MQTT,NODE-RED)

实现ESP32 MQTT网关

这个部分中,esp32将作为一个MQTT客户端订阅LED控制TOPIC,接收MQTT消息。 在解析JSON数据后,esp32将输出对应的LED控制信号。同时,ESP32也将在LED状态TOPIC上发送状态信息。

MQTT简介

在MQTT协议中,当一个用户在一个频道发送消息时,这个频道的所有订阅用户都会收到这个消息,
前提时这些用户都连接到同一个MQTT中间件。

MQTT中间件及硬件

笔者在这个项目中使用常见的开源MQTT中间件:mosquitto。
中间件可以在路由器NAT之后的本地运行,也可以在云端运行。笔者使用了一个树莓派3作为MQTT中间件的运行平台。 云端的中间件可以选择CloudMQTT,其他云服务商(比如阿里云等)也最近推出了廉价的MQTT中间件服务。

ESP32的MQTT客户端配置

笔者使用的是arduino-ide的开发环境(关于如何在arduino-ide或类似环境中开发esp32)。
arduino的MQTT库有pubsubclient,Adafruit_MQTT_Library和ArduinoMqtt等。由于arduino平台的各个硬件(arduino WIFI,ESP32,ESP8266)都有各自WifiClient的实现,MQTT库基本可以通用,很少出现不兼容问题。
笔者使用的是ArduinoMqtt库。ESP32的程序可以参考示例程序:ConnectEsp8266WiFiClient.ino。
只需要做出下列更改:
#include 换成#include
#define MQTT_ID "TEST-ID" 换成自己的MQTT客户端ID,
WiFi.begin("ssid", "passphrase");设置自己的WIFI名称和密码,
network.connect("test.mosquitto.org", 1883);里设置MQTT中间件的地址,
如果MQTT中间件访问需要用户名和密码的话,MQTTPacket_connectData options = MQTTPacket_connectData_initializer;后添加
options.username.cstring = CloudMQTTUsername; options.password.cstring = CloudMQTTPassword;

ESP32订阅话题

订阅TOPIC:

MqttClient::Error::type rc = mqtt->subscribe(
                                       MQTT_TOPIC_LED, MqttClient::QOS0, processMQTTMessage
                                     );
        if (rc != MqttClient::Error::SUCCESS) {
          LOG_PRINTFLN("Subscribe error: %i", rc);
          LOG_PRINTFLN("Drop connection");
          mqtt->disconnect();
          return;
        }

MQTT_TOPIC_LED为话题名称。
MQTT话题的格式为"AAAA/BBBB/CCC".订阅话题时可以在话题中添加通配符(wildcard)以订阅多个话题。通配符分为单级(+)和多级(#)。例如订阅"A/+/D"将会接收到“A/B/D"和”A/C/D"TOPIC的信息,但不会接收到“A/B/C/D"TOPIC的信息。多级通配符只能放在TOPIC最后一级,如“A/#"。具体请参见文档。
QOS的含义请参考MQTT文档。
订阅时可以用通配符同时订阅多个TOPIC然后在回调函数中区分消息的TOPIC,也可以为每个TOPIC编写单独的回调函数。

ESP32收到MQTT消息的回调函数

processMQTTMessage为收到消息的回调函数:

void processMQTTMessage(MqttClient::MessageData& md) {
  const MqttClient::Message& msg = md.message;
  //读取消息的TOPIC值
  char *topic = md.topicName.lenstring.data;
  int topicLen = md.topicName.lenstring.len;
  String topicname;
  for (int i = 0; i != topicLen; ++i) {
    topicname += (*topic);
    topic++;
  }
  //获得消息载荷拷贝
  unsigned char MSPpayload[msg.payloadLen];
  memcpy(MSPpayload, msg.payload, msg.payloadLen);
  
  //区分消息话题值。
  if (topicname == MQTT_TOPIC_LED_MODE) {
    if (MSPpayload[0] == 'a') {
      Serial.println("set auto");
      ledmode = MODE_AUTO;
    }
    else if (MSPpayload[0] == 'o') {
      Serial.println("set off");
      ledmode = MODE_OFF;
    }
    else if (MSPpayload[0] == 'm') {
      Serial.println("set manual");
      ledmode = MODE_MANUAL;
    }
  } else if (topicname == MQTT_TOPIC_LED_COLOR) {
    //解析JSON载荷
    JsonObject& root = jsonBuffer.parseObject(MSPpayload);
    if (!root.success()) {
      Serial.println("parseObject() failed");
    }
    else {
    //获取JSON载荷中的数据
      int red = root["red"];
      int green = root["green"];
      int blue = root["blue"];
      Serial.println(String(red) + " " + String(green) + " " + String(blue) + " ");
      //设置led数据
      setAll(red, green, blue);
      sendRMTdata();
    }
  }
}

上面的程序还使用了arduinoJSON库用来解析JSON。

ESP32发送MQTT消息

当ESP32启动并连接到中间件后将会向MQTT_TOPIC_LED_STATUS_SWITCH发送一条消息表明上线:

            const char* buf = "ON";
            MqttClient::Message message;
            message.qos = MqttClient::QOS0;
            message.retained = false;
            message.dup = false;
            message.payload = (void*) buf;
            message.payloadLen = strlen(buf);
            mqtt->publish(MQTT_TOPIC_LED_STATUS_SWITCH, message);

QOS,retained,dup的含义请参考MQTT文档。

第一部分:https://blog.csdn.net/CharlieZ8/article/details/88024897
第三部分:https://blog.csdn.net/CharlieZ8/article/details/88096061

你可能感兴趣的:(物联网控制的智能LED灯带(2):MQTT网关(WS2812/2811,ESP32,MQTT,NODE-RED))