MQTT教學(六):使用PubSubClient程式庫開發Arduino MQTT應用

本文將示範使用Arduino Uno控制板搭載乙太網路擴展板,藉由Nick O’Leary先生開發的MQTT前端程式庫,叫做PubSubClient,從Arduino發送MQTT主題訊息給Mosquitto伺服器。

PubSubClient程式庫相容於下列擴展板(shield)和控制板,完整說明請參閱此程式庫的網頁說明。

  • Arduino Ethernet
  • Arduino Ethernet Shield
  • Arduino YUN
  • Arduino WiFi Shield
  • Sparkfun WiFly Shield
  • TI CC3000 WiFi
  • Intel Galileo/Edison
  • ESP8266

此程式庫有一些功能上的限制:

  • 只能發布QoS 0訊息,但可以訂閱QoS 0或QoS 1的主題。
  • 最大訊息長度(含標頭)預設為128位元組,可透過PubSubClient.h裡的MQTT_MAX_PACKET_SIZE常數值調整。
  • keepalive(保持連線)簡隔時間預設為15秒,可透過PubSubClient.h裡的MQTT_KEEPALIVE常數值調整。
  • 用戶端預設採用MQTT 3.1.1標準,如果你的MQTT伺服器不支援(Mosquitto有支援),可將PubSubClient.h裡的MQTT_VERSION值改成3.1。

安裝PubSubClient程式庫

Arduino IDE(整合開發工具)從1.6.2版開始,支援從「程式庫管理員(Library Manager)」新增與更新程式庫的功能。選擇Arduino IDE裡的「草稿碼→匯入程式庫→管理程式庫」,開啟「程式庫管理員」。在搜尋欄位輸入關鍵字“mqtt”,可找到許多相關程式庫,請安裝PubSubClient。

程式庫管理員(Library Manager)

如果你使用的是舊版的IDE,需要手動下載安裝程式庫,請到PubSubClient專案網頁下載.zip壓縮格式檔,或者直接按此連結下載

PubSubClient專案網頁

下載之後,將它解壓縮存入「文件\Arduino\libraries」路徑。

PubSubClient程式庫提供的函式指令介紹

本節介紹稍後將使用的PubSubClient程式庫函式,完整的指令請參閱官方API文件,請先略讀本節再閱讀下一節的程式碼。

MQTT的相關指令都要透過PubSubClient物件操作,因此MQTT程式最重要的一步是建立PubSubClient物件,程式指令如下:

由於MQTT協定基於TCP/IP,因此網路層要透過其他程式庫實作。採用W5100乙太網路卡的場合,使用官方Ethernet程式庫建立TCP/IP連線,因此這裡的「網路用戶端」指的是EthernetClinet類型的物件。基於乙太網路卡,建立PubSubClient物件的敘述如下:

建立PubSubClient物件

底下是本文使用的函式指令:

setServer(MQTT伺服器, 埠號):指定欲連接的MQTT伺服器的IP位址或網域名稱,以及埠號。

connect(用戶端ID):連線到MQTT伺服器,並傳入自訂的唯一識別碼

每個MQTT用戶端都需要一個唯一的識別碼(Client ID,以下稱「用戶端ID」),MQTT伺服器透過用戶端ID來識別用戶並且紀錄個別用戶的狀態,像是訂閱的主題和通訊品質設定。根據MQTT 3.1.1規格書Client Identifier單元的說明,用戶端ID的長度為1~23個字元,並且只允許數字和英文字母。但實際的狀況視伺服器和用戶端使用的軟體而定,例如,HiveMQ公司的MQTT伺服器軟體允許用戶端ID最大長度為65535字元(參閱該公司的這篇文件說明),而MQTTLens軟體自動產生的用戶端ID長度則是32個字元(參閱下圖)。話說回來,寫程式的時候還是盡量遵循規格書訂定的規範,以減少相容性的問題。

MQTTLens軟體自動產生的用戶端ID

connected():檢查用戶端是否和伺服器連線,傳回true代表仍處於連線狀態;false代表已斷線。

publish(主題, 內容):發布主題和內容,「主題」與「內容」參數值都是字元陣列類型。此函數會傳回一個布林值,true代表發布成功,false代表不成功,可能是斷線或者訊息內容太長。

loop()程式應該要定期呼叫loop()函式,以便和伺服器保持連線並且處理接收到的訊息。loop()函式會傳回一個布林值,true代表仍與伺服器相連;false代表與伺服器斷線。

Arudino Uno搭載乙太網路擴展板發布MQTT主題訊息

本單元將以Arduino充當MQTT發布者,每隔5秒發布一則隨機溫度和濕度值(JSON格式)的“home/yard/DHT11”主題。

以Arduino充當MQTT發布者,每隔5秒發布一則隨機溫度和濕度值

實驗材料:

  • Arduino Uno控制板 × 1
  • 採用W5100晶片的乙太網路擴展板 × 1

實驗程式:

本實驗程式修改自PubSubClient程式庫內建的mqtt_basic範例,底下是程式的處理流程以及相關PubSubClient指令:

PubSubClient程式流程

此程式基於Ethernet程式庫,所以寫過Arduino HTTP伺服器或前端程式的讀者應該會感到熟悉,這是主程式部份:

底下連結MQTT伺服器的reconnect()自訂函式。

按此下載本單元的範例程式碼(.ZIP壓縮格式)

實驗結果:

我們將使用MQTTLens程式訂閱home/yard/DHT11主題,如果你之前沒有透過它訂閱過這個主題,請先訂閱,然後再把上面的程式上傳到Arduino控制板。每隔5秒,MQTTLens將顯示從Mosquitto伺服器轉送過來的訂閱訊息。

MQTTLens顯示訂閱訊息

使用String資料類型動態建立字串並轉換成字元陣列

補充說明一下建立MQTT訊息(JSON格式的字串)的敘述。這部份採用String資料類型動態建立字串,子字串和數字之間用“+”運算子相連。連接字串的最前面要加上這個String類型變數(msgStr),否則編譯過程將引發資料類型錯誤。由於publish()函式的參數值為字元陣列格式,因此程式要先透過String物件的toCharArray()方法,把String類型的字串轉換成字元陣列格式。

使用String資料類型動態建立字串並轉換成字元陣列

筆者將字元陣列的長度(元素數量)設定成25,足夠此範例的JSON字串使用,如有需要,請自行調整json陣列變數的長度。

延伸閱讀

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *