顯示具有 MQTT 標籤的文章。 顯示所有文章
顯示具有 MQTT 標籤的文章。 顯示所有文章

2021年6月12日 星期六

再論 - 微型物聯網 (IoT) 架構 - MQTT

IoT 最重要的莫過於網路通訊了,機器與機器 ( M2M ) 間需要透過 HTTP 來傳輸資料,了解比較深入的人,可能還知道 CoAP 或 MQTT 等。

MQTT 是一種物聯網的通訊協定,最初是由 IBM 和 Eurotech 主導開發,並已在 2014 年正式成為了 OASIS 國際標準,開發的目的是為了在窄寬帶以及低耗能條件下,傳送與接收處理訊息,採用 Publish/Subscribe 的方式,透過 Broker 做訊息溝通。

MQTT 的標頭 ( header ),僅佔 2 個 bytes ,縮小了傳輸量。整體來說,資料封包也比要傳送同等訊息的 HTTP 來的小,這種特性讓 MQTT 非常適合運用在現行的 IoT 架構中。

Publisher、Subscriber、Broker 又是什麼?

Publish / Subscribe 為一種訊息規範的模式 :

發布者:Publisher,不會將訊息直接傳送給訂閱者:Subscriber,而是將訊息分為不同的主題:Topic,訂閱者只接收已訂閱的主題。

MQTT 即是採用 Publish/Subscribe 模式,其中 Publisher 和 Subscriber 都是用戶端(Client),Broker是伺服器端(Server) 負責轉發 Topic。

Publish / Subscribe 示意圖

Subscriber 告知 Broker 想要訂閱的 Topic,每當 Publisher 發布訊息時,Broker 會依照 Topic,傳送給訂閱的 Subscriber。

由於 PublisherSubscriber 之間有 Broker 當作中繼站,所以兩邊並不需要知道彼此的 IP。

IBM Watson IoT Platform from https://www.ibm.com/developerworks/
Topic 主題格式

MQTT 的 Topic 是字串 ( String ),並支援階層式命名如下範例:

outside/temperature/temp_Device01
inside/humidity/humid_Device07
Taiwan/Taipei/Datong/ChengdeRoad/Traffic
...

階層數沒有固定,但是要特別注意的是,英文的大小寫是有區別的,且長度不可超過 65536 個字元。

品質 ( Qos ) 設定

MQTT 定義了三個層級的品質 ( Qos:0、1、2 ),分別適用於不同的情況:

Qos 0:at most once 最多傳一次
在「Qos:0」的設定下,訊息送出後就不管了,由於 MQTT 是屬於網路架構中的應用層,它並不會知道底層的網路斷線與否,所以 Broker 是有可能沒收到訊息的。如果你的目標裝置接的是有線網路,或者,遺漏幾筆資料也不會對結果造成太大影響的情況下 ( 樣本數夠多 ),可以使用這個設定。

Qos 0:示意圖

Qos 1:at least once 至少傳一次
Broker 從 Publisher 收到「Qos:1」的訊息之後,會回應一個 PUBACK,以確認有收到訊息。如果連線中斷或其他狀況導致 Publisher 沒有收到 PUBACK,Publisher 就會重新發送,保證訊息至少傳送至 Broker 一次。

Qos 1:示意圖
然而,假設 Broker 有收到訊息,但在回應給 Publisher 時,中間發生斷線或故障。Publisher 會認為 Broker 沒有收到而重送,結果導致 Broker 重複收到同一份訊息。
QoS1:Broker 有收到訊息 但 Publisher 沒收到 PUBACK

Qos 2:exactly once 確實傳送一次
「Qos:2」設定比「Qos:1」更嚴謹了一些。它將發送訊息分成了幾段:

Broker 收到「Qos:2」的訊息之後,將回覆 PUBREC 給 Publisher,表示收到了即將發布的訊息,並暫存訊息的封包識別碼,以防止因斷線或逾時,需重新傳送而造成的重複。

Publisher 如果收到了 PUBREC,會再傳送 PUBREL 給 Broker,告訴 Broker 可以釋放訊息了。此時 Broker 會把訊息傳送給 Subscriber,然後回應 PUBCOMP 告訴 Publisher 已經發送完畢,並刪除暫存訊息。

Qos 2:示意圖

相較於「Qos:1」,「Qos:2」會佔用比較多的網路和傳送時間,但能確實傳送一次訊息。

最後,究竟為什麼要使用 MQTT?
IoT picture from https://www.freepik.com/

在 IoT 的世界裡,末端的裝置動輒數百上千,一來一往的數據傳輸量很是驚人,流量那麼大的情況下,網路使用費計算起來也是相當可觀,並不是每個地方都可以享有吃到飽的服務,因此,封包傳輸量較小、能一對多的 MQTT 就成了主流之一。

除此之外,品質 Qos 的設計也可以讓不同的裝置甚至不同的架構需求,使用合適的品質設定來傳送資料,以符合最佳的應用情境。

2021年5月25日 星期二

什麼是 MQTT?

MQTT是由 IBM 的 Andy Stanford-Clark 博士和 Arcom(已更名為 Eurotech)的 Arlen Nipper 博士於 1999 年發明的通訊協定。他們當時是為了在狹窄的網路頻寬和微小電力損耗的需求前提之下,提供石油管線感測器和人造衛星之間一個輕量、可靠的二進制通訊協定。2011 年 11 月,IBM 和 Eurotech 將 MQTT 協定捐贈給負責管理開放原始碼專案的 Eclipse 基金會,並且加入 Eclipse M2M Industry 工作組織。2014 年十月,MQTT 正式變成一個開放的 OASIS 國際標準(Organization Advancement Structured Information Standards,資訊標準架構促進會,一個制定電子商務、網路服務和電子出版的非營利機構)。

MQTT 最初代表的意思是 Message Queueing Telemetry Transport(訊息佇列遙測傳輸),現在已經不用這種說法,MQTT 就是 MQTT,不是其他單字的縮寫。由於 MQTT 協定的訊息內容很精簡,非常適合用於處理器資源及網路頻寬有限的物聯網裝置,再加上已經有許多 MQTT 程式庫被陸續開發出來,用於 Arduino 控制板(C/C++)、JavaScript(Node.js, Espruino 控制板),Python …等等,還有開放原始碼的 MQTT 伺服器,使得開發 MQTT 物聯網、機器之間(Machine-to-Machine, M2M)的通訊變得非常簡單。Facebook Messenger 的即時通訊也是用 MQTT 協定。

採用 Arduino 和 ESP8266 實作 MQTT 之前,我們先探討有關 MQTT 的背景知識和一些術語說明。

比較 HTTP 和 MQTT 通訊協定

MQTT 和 HTTP 的底層都是 TCP/IP,也就是物聯網裝置可以沿用既有的網路架構和設備,只是在網路上流通的「訊息格式」以及應用程式的處理機制不同。

某個裝置透過 Web 瀏覽器,以 HTTP 協定傳送溫度值給網站伺服器,此 HTTP POST 訊息內容大概像這樣:

除了 HTTP 請求指令以及代表 21 度的訊息本體,這段訊息中間夾帶了一堆描述用戶端的的標頭(header)資訊,相當於向伺服器介紹:我來自 Chrome 瀏覽器、作業系統是 Android 7、我讀懂中文和英文…等等。這些額外的標頭訊息在許多物聯網通訊應用不僅僅是多餘的,還會佔用網路頻寬、記憶體並且浪費處理時間。

MQTT 訊息格式

採用 MQTT 發布溫度的訊息格式類似這樣:

不同於 HTTP 的標頭採用文字描述,MQTT 的標頭採用數字編碼,整個長度只佔 2 位元組,等同兩個字元,後面跟著訊息的主題(topic)和內容(payload),實際格式如下:

MQTT 標頭裡的訊息類型、品質…等內容,留待下文說明。除了精簡的標頭,讀者可以發現,MQTT 的標頭區並沒有標示傳送目標的 IP 位址。

MQTT 的 Publisher、Broker 和 Subscriber

根據 MQTT 3.1.1 版本規格書的描述,MQTT 是一種基於「發布∕訂閱」機制的訊息傳輸協定(MQTT is a Client Server publish/subscribe messaging transport protocol),我們可以把它想成雜誌發行和訂閱的機制。MQTT 訊息發送端,相當於雜誌出版社,雜誌出版之後並不直接寄給消費者,而是交給經銷商或者書店一般的代理人(broker),來統籌管理發行和訂閱事宜。每一個訊息來源(刊物)都有個唯一的主題名稱(刊物名稱)。

代理人是個伺服器軟體,向伺服器發送主題的一方是發布者(publisher),從伺服器獲取主題的一方則是訂閱者(subscriber)。以下圖為例,傳送感測器資料的一邊是發布者,接收感測器資料的一邊則是訂閱者。每個感測器∕微控器的訊息都需要有個主題名稱以利識別,像下圖的主題 A、B 和 C。

代理人(broker)可儲存發布者的訊息,在發布者中斷連線的情況下,提供訂閱者最近更新的訊息。「訂閱者」需要告知代理人想要訂閱的主題,每當「發布者」傳入新訊息時,代理人就會依照主題,傳送給所有訂閱者。「發布者」和「訂閱者」都是用戶端,代理人是伺服器。由於兩個用戶端之間有伺服器當作中繼站,所以兩邊並不需要知道彼此的IP位址。

MQTT 的主題(Topic)名稱

MQTT 主題名稱是 UTF-8(萬國碼)編碼的字串,我們可以自行決定主題名稱,例如,傳送溫度的訊息主題可命名成「溫度」、傳送亮度的訊息主題叫做「照度」…等等。主題名稱也支援類似檔案路徑的階層式命名方式,假設住家裡面有許多感測器,我們可依照測器所在位置,規劃如下的命名階層結構:

每個階層之間用斜線分隔,例如,位於庭院的人體感測器 #1,其主題名稱可命名為:

    命名主題的注意事項:
  • 由於某些微控器或程式語言不支援 UTF-8 編碼或中文,主題名稱請使用英文,並且取個有意義的名字。
  • 名稱長度不可超過 216 位元組(65536個字元)。
  • 自訂的主題名稱請勿用 $ 開頭(“$SYS”是 MQTT 伺服器的控制介面主題的保留字),也不可包含 # 和 + 字元;減號和乘號(*)在程式語言中有特殊意義,為了避免誤會,也不建議使用。
  • 名稱的英文大小寫有區別,home 和 Home 是兩個不同的名稱。
  • 雖然名稱可以包含空格,但是英文的「半形」空格和中文的「全形」空格的內碼不一樣,若輸入名稱時沒有統一,會導致程式讀取不到,因此名稱最好不要加入空格。
  • 階層名稱可以空白,像這樣的命名(連續的斜線)是合法的:“home//yard”,代表有三個階層,中間階層沒有名字,在語意上怪怪的。
  • 有些程式設計師習慣在主題名稱最前面加上一個斜線(在 Linux 系統中,檔案路徑開頭的斜線代表根目錄),但這是不必要的。請注意,“/home” 和 “home” 是兩個不同的名稱,前者代表「空白名稱的根階層」底下的 “home”,單一個 “/” 也是合法的名稱。
  • 除了依據裝置安裝地點來命名主題,當同一個地點包含許多感測器的時候,用編號或者唯一識別碼來命名主題是比較合理的選擇。例如,假設某個位於廚房的裝置的 MAC 位址是 DEADBEEFFEED,它可以被命名成:

    Home/kitchen/DEADBEEFFEED