MQTT協議 - arduino ESP32 通過精靈一號 MQTT Broker 進行通訊的程式碼詳解

靈感桌面發表於2021-12-17

前言

之前研究了一段時間的 COAP 協議結果愛智那邊沒有測試工具,然後 arduino 也沒有找到合適的庫,我懶癌發作也懶得修這庫,就只能非常尷尬先暫時放一放了。不過我在 愛智APP -> 裝置 -> 設定 中發現愛智中做了一個 MQTT Broker ,也就是說我能利用精靈一號,在兩塊ESP32 之間進行通訊了,而且 arduino 也有現成的庫,然後我就突擊了一下MQTT ,把這玩意給弄起來了,這裡就給大家分享一下。
在這裡插入圖片描述

配置 MQTT Broker

在愛智APP的裝置中有個設定按鈕:

在這裡插入圖片描述
在裡面可以啟用精靈一號的 MQTT Broker 功能並且進行設定:
在這裡插入圖片描述
在 MQTT 的設定中可以配置相關引數:
在這裡插入圖片描述
這些引數和與下面 ESP32 中的配置有關

程式碼獲取

我使用的 MQTT 庫直接在 IDE 的庫管理器裡就能下載到:
在這裡插入圖片描述
或者去GitHub下載:

https://github.com/adafruit/Adafruit_MQTT_Library

而示例程式碼,老樣子在靈感桌面的祕密寶庫 下載程式碼。
或者直接 git clone:

https://gitee.com/inspiration-desktop/eap-energy-conservation.git

在這裡插入圖片描述
裡面有兩個資料夾,分別是釋出者和訂閱者發的示例。

程式碼解析

為了方便講解邏輯,我會打亂程式碼的順序可能還會進行裁剪。本 demo 基於 MQTT 庫自帶的 DEMO 修改而來。

建立 MQTT 客戶端

#include <WiFi.h>
//#include "WiFiClientSecure.h"
#include "WiFiClient.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

/************************* WiFi Access Point *********************************/

#define WLAN_SSID "EOS-Tenda"
#define WLAN_PASS "1234567890"

/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER      "192.168.128.1"

// 在愛智APP->裝置->MQTT Broker 設定,可以看到並且設定
#define AIO_SERVERPORT  1883

// 在愛智APP->裝置->MQTT Broker 設定,可以看到並且設定
#define AIO_USERNAME "user"
#define AIO_KEY      "passwd"

/************ Global State (you don't need to change this!) ******************/

// 愛智似乎沒有這個安全模式,於是使用了 WiFiClient 
//WiFiClientSecure client;
WiFiClient client;

// 通過傳入WiFi客戶端和MQTT服務端以及登入詳細資訊來設定MQTT客戶端類,注意連入愛智必須設定 cid,可能和愛智那邊設定有關係。
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, "Publish_cid", AIO_USERNAME, AIO_KEY);

需要注意的是雖然 Adafruit_MQTT_Client 有可以不帶 cid 的實現

/***
 * 函式1:建立MQTT客戶端
 * @param client 來源客戶端,比如Wificlient eth乙太網
 * @param server  mqtt伺服器地址
 * @param port    mqtt伺服器埠
 * @param cid     客戶端id,如果是8266,可以設定為晶片id之類的,每個端都是獨一無二
 * @param user    mqtt伺服器賬號
 * @param pass    mqtt伺服器密碼
 */
Adafruit_MQTT_Client(Client *client, const char *server, uint16_t port,
                       const char *cid, const char *user, const char *pass):
    Adafruit_MQTT(server, port, cid, user, pass),
    client(client)
{}

/***
 * 函式2:建立MQTT客戶端
 * @param client 來源客戶端,比如Wificlient eth乙太網
 * @param server  mqtt伺服器地址
 * @param port    mqtt伺服器埠
 * @param user    mqtt伺服器賬號
 * @param pass    mqtt伺服器密碼
 */
Adafruit_MQTT_Client(Client *client, const char *server, uint16_t port,
                       const char *user="", const char *pass=""):
    Adafruit_MQTT(server, port, user, pass),
    client(client)
————————————————
版權宣告:本文為CSDN博主「微控制器菜鳥哥」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/dpjcn1990/article/details/103376117

但是連線愛智時 Adafruit_MQTT_Client 函式必須設定 cid 而且 cid 必須是獨一無二的,否則:
在這裡插入圖片描述
cid 重複會導致這兩個裝置收到同樣的,重複的連線成功訊息,使裝置不停的去連線精靈一號

建立 MQTT 釋出主題

// 設定一個名為“test”的提要用於釋出。
// 注意AIO的MQTT路徑遵循: <username>/feeds/<feedname>
Adafruit_MQTT_Publish test = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/test");

建立 MQTT 訂閱主題

// 設定訂閱的主題。
Adafruit_MQTT_Subscribe test = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/test");

初始化流程

void setup() {
  Serial.begin(115200);
  delay(10);

  Serial.println(F("Adafruit IO MQTTS (SSL/TLS) Example"));

  // Connect to WiFi access point.
  Serial.println(); Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);

  delay(1000);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  delay(2000);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.println("WiFi connected");
  Serial.println("IP address: "); Serial.println(WiFi.localIP());

  
// 設定測試需要的 MQTT 訂閱。釋出者把這一行註釋掉
  mqtt.subscribe(&test);
}

MQTT 連線

// 函式用於根據需要連線並重新連線到MQTT伺服器
// 應該在迴圈函式中呼叫,它將注意是否連線。
void MQTT_connect() {
  int8_t ret;

  // 如果已經停止連線。
  if (mqtt.connected()) {
    return;
  }

  Serial.print("Connecting to MQTT... ");

  uint8_t retries = 3;
  // 連線mqtt伺服器
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
       Serial.println(mqtt.connectErrorString(ret));
       Serial.println("Retrying MQTT connection in 5 seconds...");
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds
       retries--;
       if (retries == 0) {
         // basically die and wait for WDT to reset me
         while (1);
       }
  }

  Serial.println("MQTT Connected!");
}

釋出者協議主迴圈

void loop() {
  // 確保到MQTT伺服器的連線是活動的(這將建立第一個連線,
  // 並在斷開連線時自動重新連線)。請參閱上面的MQTT_connect函式定義。
  MQTT_connect();

  // 現在我們可以釋出東西了!
  Serial.print(F("\nSending val "));
  Serial.print(x);
  Serial.print(F(" to test feed..."));
  if (! test.publish(x++)) {
    Serial.println(F("Failed"));
  } else {
    Serial.println(F("OK!"));
  }

  // wait a couple seconds to avoid rate limit
  delay(2000);

}

訂閱者協議主迴圈

void loop() {
  // 確保到MQTT伺服器的連線是活動的(這將建立第一個連線,
  // 並在斷開連線時自動重新連線)。請參閱上面的MQTT_connect函式定義。
  MQTT_connect();
  
  // 等待訂閱訊息迴圈
  Adafruit_MQTT_Subscribe *subscription;
  // 在5s內判斷是否有訂閱訊息進來
  while ((subscription = mqtt.readSubscription(5000))) 
  {
    Serial.println("subscription");
    // 判斷是否是我們對應的主題
    if (subscription == &test)
    {
      Serial.print(F("Got: "));
      // 列印主題資訊內容
      Serial.println((char *)test.lastread);
    }

  // wait a couple seconds to avoid rate limit
  delay(2000);
  }
}

總結

在這裡插入圖片描述
精靈一號的 MQTT Broker 還是好用的,兩個 ESP32 板子完美的通訊了。

相關文章