MQTT 的全名是 Message Queuing Telemetry Transport,目前最新的版本為 MQTT v5.0,目前廣泛使用的是 MQTT v3.1。
由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,資訊標準架構促進會,一個制定電子商務、網路服務和電子出版的非營利機構,https://www.oasis-open.org/)。
是一種適用於 Server 與 Client 訊息傳遞的通訊協定,此協定建構在 TCP/IP Stack 上,利用『訂閱 Subscribe』與『發佈 Publish』的機制來進行訊息傳遞。因為其訊息結構簡單且輕量化,非常適合用於處理器資源及網路頻寬有限的物聯網裝置,再加上已經有許多 MQTT 程式庫被陸續開發出來,用於 Arduino 控制板(C/C++)、JavaScript(Node.js, Espruino控制板)、Python,…等等,還有開放原始碼的 MQTT 伺服器,使得開發 MQTT 物聯網、機器之間(Machine-to-Machine, M2M)的通訊變得簡單。Facebook Messenger的即時通訊也是用MQTT協定。
假設某個裝置透過 Web 瀏覽器,以 HTTP 協定傳送溫度值給網站伺服器,此 HTTP POST 訊息內容大概像這樣:
除了 HTTP 請求指令以及代表 21 度的訊息本體,這段訊息中間夾帶了一堆描述用戶端的的標頭(header)資訊,相當於向伺服器介紹:我來自Chrome瀏覽器、作業系統是Android 7、我讀懂中文和英文…等等。這些額外的標頭訊息在許多物聯網通訊應用不僅僅是多餘的,還會佔用網路頻寬、記憶體並且浪費處理時間。
除了精簡的標頭,MQTT 的標頭區並沒有標示傳送目標的 IP 位址。
在 MQTT 訊息中,『Control Header』 跟『Remaining Length』這兩個部分都是必須存在,後面的『 Variable Header 』跟 『Payload』 則是依據傳送需求決定,如果以 Publish Message 來說,Variable Header 就會放入 topic 主題,Payload 區塊就是欲傳遞的訊息內容。
在 MQTT 的架構下,會有3種角色:Broker 代理人、Publisher 訊息發佈者、Subscriber 訊息訂閱者。 Broker 負責接收來自 Publisher 的訊息並『配發』訊息給 Subscriber,Publisher 是訊息源頭,也就是發佈訊息的人,Subscriber 也就是接收訊息的人。
假設你今天有個資料擷取裝置比如溫濕度感測器,想要透過 MQTT 的通訊傳遞溫度與濕度訊息到不同的裝置(多個PC或手機)使用,Publisher 就可以是溫濕度感測器,定時的送出溫度濕度資訊,Subscriber 就可以是 不同 PC 和手機,Broker 的工作就是接收來自感測器的訊息,轉送給 PC 與 手機,至於 Broker 怎麼決定訊息要轉送或配發給誰,Topic 主題就是關鍵的點,你有訂閱該 Topic,Broker才會配發給你。
代理人(broker)可儲存發布者的訊息,在發布者中斷連線的情況下,提供訂閱者最近更新的訊息。「訂閱者」需要告知代理人想要訂閱的主題,每當「發布者」傳入新訊息時,代理人就會依照主題,傳送給所有訂閱者。「發布者」和「訂閱者」都是用戶端,代理人是伺服器。由於兩個用戶端之間有伺服器當作中繼站,所以兩邊並不需要知道彼此的IP位址。
MQTT 主題名稱是UTF-8(萬國碼)編碼的字串
自行決定主題名稱,例如,傳送溫度的訊息主題可命名成「溫度」、傳送亮度的訊息主題叫做「照度」…等等。
主題名稱也支援類似檔案路徑的階層式命名方式,假設住家裡面有許多感測器,我們可依照測器所在位置,規劃如下的命名階層結構。
命名主題的注意事項:
由於某些微控器或程式語言不支援UTF-8編碼或中文,主題名稱請使用英文,並且取個有意義的名字。
名稱長度不可超過216位元組(65536個字元)。
自訂的主題名稱請勿用$開頭(“$SYS”是MQTT伺服器的控制介面主題的保留字),也不可包含#和+字元;減號和乘號(*)在程式語言中有特殊意義,為了避免誤會,也不建議使用。
名稱的英文大小寫有區別,home和Home是兩個不同的名稱。
雖然名稱可以包含空格,但是英文的「半形」空格和中文的「全形」空格的內碼不一樣,若輸入名稱時沒有統一,會導致程式讀取不到,因此名稱最好不要加入空格。
MQTT 還有幾個重要特色
在訊息傳遞的過程中,Publisher 不需要知道 Subscriber 的 IP,只需要知道 Broker 的位址就可以進行訊息傳遞。
MQTT 的 Topic 主題帶有階層式設計,用 / 來分開,比如說工廠會議室的溫度與濕度,就可以編寫成 factory/meeting/temp 與 factory/meeting/humid,英文大小寫是有差的。
由於 MQTT 是設計允許在網路環境較差地方運行,所以針對網路的品質(QoS),使用者可以自己決定操作等級:
QoS Level 0:發送者丟出一次訊息給 Broker,並不保證 Subscriber 會收到。
QoS Level 1:Publisher 丟出訊息後,Broker 必須回傳 PUBACK 訊息確定有收到,如沒回,Publisher 會再重傳一次。(缺點為 Subscriber 有可能會收到相同的訊息)
QoS Level 2:在 Publisher 確認 Broker 有收到訊息後,Broker 才可進行訊息傳遞,且 Subscirber 在收到訊息後,也必須回傳 PUBCOMP 訊息給 Publisher,此方法可以避免收到重複的訊息,但缺點就是較佔頻寬。
QoS代表發布者與代理人,或者代理人與訂閱者之間的傳輸品質。MQTT 定義了0, 1和2三個層級的品質設定(實際支援情況依伺服器軟體而定,Mosquitto伺服器全都支援):
0:最多傳送一次(at most once)
1:至少傳送一次(at least once)
2:確實傳送一次(exactly once)
MQTT裝置之間的訊息傳遞基於TCP/IP,在正常連線狀態下,TCP能確保訊息封包都能抵達目的地。在網路階層架構中,「MQTT程式」屬於應用層,它產生的訊息交給下一層(TCP)處理,但MQTT程式並不清楚最底層的網路是否壅塞甚至斷線,所以才說,MQTT不保證能交付訊息。
QoS 1品質設定則像寄送掛號信;收訊者(如:代理人)收到訊息之後,會回應PUBACK訊息(publish acknowledgement,發布確認)給發布者,確認有收到訊息。在「品質」設定為1或2的情況下,MQTT訊息檔頭後面會夾帶一個稱為packetId(封包ID)的識別碼,收訊者回應的PUBACK訊息也會傳回相同的識別碼提供發布者確認。
QoS 1品質設定則像寄送掛號信;收訊者(如:代理人)收到訊息之後,會回應PUBACK訊息(publish acknowledgement,發布確認)給發布者,確認有收到訊息。在「品質」設定為1或2的情況下,MQTT訊息檔頭後面會夾帶一個稱為packetId(封包ID)的識別碼,收訊者回應的PUBACK訊息也會傳回相同的識別碼提供發布者確認。
假如一段時間過後,發布者沒有收到PUBACK回應,它會認定訊息沒有送達,因而重新傳送一次訊息。然而,如果代理人有收到訊息,但是在它傳送回應時,發布者因連線故障而漏接回應。發布者會誤以為對方沒收到訊息而再次傳送,導致訂閱者重複收到相同訊息。
QoS 2設定。在此設定模式之下,當收訊者收到訊息時,它將回覆PUBREC(publish received,已收到發布訊息),並且暫存訊息的「封包識別碼」,以防重複處理相同的訊息。當發布者收到PUBREC回應時,將傳送PUBREL(publish release,釋放發布訊息)給代理人,代理人會先把訊息傳送給訂閱者,然後回應PUBCOMP(publish complete,發布完成)並刪除之前暫存的訊息。
The Public MQTT Broker by HiveMQ – Check out our MQTT Demo – broker.hivemq.com:1883, broker.hivemq.com:8000
broker.mqtt-dashboard.com:broker.mqtt-dashboard.com:1883, broker.mqttdashboard.com:8000
test.mosquitto.org – test.mosquitto.org:1883
mqtt.eclipseprojects.io – mqtt.eclipseprojects.io:1883
ESP8266 连接到免费的公共 MQTT 服务器 – broker.emqx.io:1883
通信猫 共享MQTT服务器 在线客户端 – mq.tongxinmao.com:18830
夜市小霸王 - mqttgo.io:1883
安裝 MQTT Server 於本機(桌機、筆電),提供 MQTT 服務。
透過 Client 端軟體測試 publish 和 subscribe 功能,用以確認 Public MQTT Broker 運作正常;熟悉Client 端操作。
透過 Client 端軟體測試 publish 和 subscribe 功能,用以確認架設的 MQTT Broker 運作正常;熟悉Client 端操作。
以 NodeMCU 為 MQTT Client 端,當訊息發布者,以命令提示字元、手機 App、Chrome 擴充為 MQTT Client 端,當訊息接收者。
以 NodeMCU 為 MQTT Client 端,當訊息接收者,以命令提示字元、手機 App、Chrome 擴充為 MQTT Client 端,當訊息發布者。
以多 NodeMCU 為 MQTT Client 端,當訊息接收或發布者。
MQTTLens 應用程式(Chrome 擴充)安裝。
MQTTBox 應用程式(Chrome 擴充)安裝。
MQTT Dash App 安裝。
IoT OnOff App 安裝(安卓、iOS)
MQTTool(iOS)
MQTTLens 是 Chrome 瀏覽器的應用程式,將它加入Chrome。
Chrome 擴充安裝完成,於瀏覽器網址處輸入 chrome://apps/ 或點選應用程式可看到
Chrome 擴充安裝完成,於瀏覽器網址處輸入 chrome://apps/ 或點選應用程式可看到
Mqtt Dash App 由 Google Play 商店安裝,搜尋 mqtt,(1120407)已無法安裝,改 apk 安裝 https://m.apkpure.com/tw/mqtt-dash-iot-smart-home/net.routix.mqttdash
Google Play 商店,(1120407)已無法安裝,改 apk 安裝
https://m.apkpure.com/tw/mqtt-dash-iot-smart-home/net.routix.mqttdash
開啟瀏覽器,連線 http://www.hivemq.com/demos/websocket-client/ 使用
以 test.mosquitto.org 當 Public MQTT Server,
分別以 MQTTBox, MQTTLns, 手機 MQTT Dash App 當 MQTT Client,練習訂閱/發布
開瀏覽器,網址列輸入 chrome://apps,從 chrome 應用程式開啟 MQTTBox
新增 MQTT Client 連線
Host 輸入MQTT 服務器 test.mosquitto.org,Name 自取。這裡測試匿名連線,Username, Password 不必給
連線成功,顯示 Connected
MQTTBox 設定發布,
發布 JSON 字串 {"temp":31, "humid":34} 至 dellnb/06111017/test 主題
MQTTBox 設定訂閱
開瀏覽器,網址列輸入 chrome://apps,開啟 MQTTLens
新增連線
設定
發布: Topic: temp/mqttLens
訂閱:Topic: temp/cmd
執行 Mqtt Dash App
新增 MQTT 連線
執行手機 Mqtt Dashboard App,新增建立 test.mosquitto.org 連線
接下來要在 連線中建立控制面板(dashboard)
選連線名稱,進入控制面板
新增文字型控制項,當訂閱者
設定完成,儲存
新增控制項,當發布者
要修改控制項,對著該控制項長按,選 Edit
於 test.mosquitto.org 連線中,建立發布訂閱
發布
以 NodeNCU 當發布端,將感測器測量資料發布到 public MQTT Server(broker.hivemq.com、test.mosquitto.org)
分別以下列 MQTT Client 當訂閱端,接收資料並展示
MQTT Box、MQTT Lens
MQTTX
MQTT Dash App、IoT OnOff App
Node-Red
草稿碼 > 匯入程式庫 > 管理程式庫
使用的 Public MQTT Server:broker.hivemq.com:1883
發布主題
topic1: ymiot1122/00000/ldrA
topic2: ymiot1122/00000/ldrD
topic3: ymiot1122/00000/dhtT
topic4: ymiot112200000/dhtH
或 離線版 TUNIOT(執行資料夾中 demo/code/index.html)
IOT > Web Services > MQTT Connect
#include <PubSubClient.h>
WiFiClient espClient;
PubSubClient client(espClient);
setup()
client.setServer("", 1883);
client.setCallback(callback);
IOT > Web Services > MQTT Connect to server
void reconnectmqttserver() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str())) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
IOT > Web Services > MQTT Function Callback
void callback(char* topic, byte* payload, unsigned int length) {
String MQTT_DATA = "";
for (int i=0;i<length;i++) {
MQTT_DATA += (char)payload[i];}
}
IOT > Web Services > MQTT loop
loop()
if (!client.connected()) {
reconnectmqttserver();
}
client.loop();
IOT > Web Services > MQTT Publish
loop()
snprintf (msgmqtt, 50, "%d ","");
client.publish("TOPIC", msgmqtt);
randomSeed(analogRead(0));
儲存積木檔(.xml),儲存 Arduino 程式碼(.ino)
connect MQTT Server
建立四個訂閱
topic1:ymiot/1101A/810000/test01
topic2:ymiot/1101A/810000/test02
執行 Mqtt Dash App
新增 MQTT 連線
1 自行命名
2 使用的 MQTT Server 名稱,本課程使用 broker.hivemq.com
3 儲存
選定建立的 MQTT Server,建立控制項
1 選連線名稱
2 新增控制項
MQTT Dash 提供六種控制項,我們課程會使用到四種
3 建立 Range 控制項
1 自行命名
2 訂閱的主題
3 如果該控制項同時業也要做發布使用,勾選此選項。這兒控制項只當訂閱用,取消勾選。
4 自訂資料範圍
5 自訂顏色
6 儲存設定
完成的控制項如下:
建立 Switch/button 控制項
1 自行命名
2 訂閱的主題
3 如果該控制項同時業也要做發布使用,勾選此選項。這兒控制項只當訂閱用,取消勾選。
4 接收到訊息內容
5 接收到 4 的訊息要呈現的圖案
6 接收到 4 的訊息要呈現的圖案顏色
7 接收到訊息內容
8 接收到 7 的訊息要呈現的圖案
9 接收到 7 的訊息要呈現的圖案顏色
10 儲存設定
建立 Switch/button 控制項
以系統管理員身分執行命令提示字元
輸入 node-red,執行 node-red
開瀏覽器,連結 http://127.0.0.1:1880/
Dashboard 分頁
新增 Tab(頁籤):一個 tab 就是網頁顯示時的一個分頁
編輯 Tab(頁籤)
新增 group(群組):群組是顯示控制項的"容器"
編輯 group(群組)
群組名,自取
將群組至於哪一個 Tab(分頁)中
群組容器寬度
等設計完成,且佈署後,可按此連結開啟展示網頁(http://127.0.0.1:1880/ui/),
或直接於瀏覽器網址列輸入 http://127.0.0.1:1880/ui/,也可開啟展示網頁
下載預設檔名:flows.json
選取要會匯入的流程檔( .json)
節點
網路 > mqtt in,名稱:hivemq data1
網路 > mqtt in,名稱:hivemq data2
網路 > mqtt in,名稱:hivemq data3
網路 > mqtt in,名稱:hivemq data4
dashboard > chart,名稱:simulatedData1
dashboard > gauge,名稱:simulatedData2
dashboard > gauge,名稱:simulatedData3
dashboard > gauge,名稱:simulatedData4
編輯 1
編輯 2
編輯 3
編輯 4
編輯 5
編輯 6
編輯 7
編輯 8
dashboard 布局
編輯群組
按此開啟 UI 網頁
Arduino IDE 開啟載入程式碼(.ino),選擇正確控制板,選擇正確連接埠,上傳燒錄。
開啟序列部視窗,設定傳輸速率 9600,確認成功連上 MQTT Server。
使用的 Public MQTT Server:broker.hivemq.com:1883
發布主題
topic1: ymiot/1101A/00000/ldrA
topic2: ymiot/1101A/00000/ldrD
topic3: ymiot/1101A/00000/dht11T
topic4: ymiot/1101A/00000/dht11D
開瀏覽器,連線
或 離線版 TUNIOT(執行資料夾中 demo/code/index.html)
完成之積木程式
dht4.begin();
儲存積木檔(.xml),儲存 Arduino 程式碼(.ino)
下載 Node.js/安裝
下載安裝
確認 Node.js and npm 正確安裝
安裝完成,執行命令提示字元,輸入
node --version && npm --version
於 Powershell,輸入
node --version; npm --version
C:\Windows\system32>node --version && npm --version
v18.16.0
9.5.1
C:\Windows\system32>npm install npm --global
C:\Windows\system32>npm --version
9.6.5
以系統管理員身分執行命令提示字元
以系統管理員身分執行命令提示字元,輸入
npm install -g --unsafe-perm node-red
於 Node JS v18.16.0 或 Windows11,上述方法無法安裝(原因不明),須執行 Node.js command prompt 安裝
於 Node.js command prompt,輸入
npm install -g --unsafe-perm node-red
測試版安裝用 npm install -g --unsafe-perm node-red@next
以系統管理員身分執行命令提示字元
輸入 node-red,執行 node-red
C:\Users\PYMHS>node-red
20 Aug 15:46:03 - [info]
Welcome to Node-RED
===================
20 Aug 15:46:03 - [info] Node-RED version: v2.0.5
20 Aug 15:46:03 - [info] Node.js version: v14.17.5
20 Aug 15:46:03 - [info] Windows_NT 10.0.19043 x64 LE
20 Aug 15:46:04 - [info] Loading palette nodes
20 Aug 15:46:05 - [warn] Missing node modules:
20 Aug 15:46:05 - [warn] - node-red-node-rbe (0.5.0): rbe
20 Aug 15:46:05 - [warn] - node-red-node-tail (0.3.1): tail
20 Aug 15:46:05 - [info] Removing modules from config
20 Aug 15:46:05 - [info] Settings file : C:\Users\PYMHS\.node-red\settings.js
20 Aug 15:46:05 - [info] Context store : 'default' [module=memory]
20 Aug 15:46:05 - [info] User directory : \Users\PYMHS\.node-red
20 Aug 15:46:05 - [warn] Projects disabled : editorTheme.projects.enabled=false
20 Aug 15:46:05 - [warn] Flows file name not set. Generating name using hostname.
20 Aug 15:46:05 - [info] Flows file : \Users\PYMHS\.node-red\flows_M4630-1388.json
20 Aug 15:46:05 - [info] Creating new flow file
20 Aug 15:46:05 - [warn]
---------------------------------------------------------------------
Your flow credentials file is encrypted using a system-generated key.
If the system-generated key is lost for any reason, your credentials
file will not be recoverable, you will have to delete it and re-enter
your credentials.
You should set your own key using the 'credentialSecret' option in
your settings file. Node-RED will then re-encrypt your credentials
file using your chosen key the next time you deploy a change.
---------------------------------------------------------------------
20 Aug 15:46:05 - [info] Server now running at http://127.0.0.1:1880/
20 Aug 15:46:05 - [info] Starting flows
20 Aug 15:46:05 - [info] Started flows
開啟 Node.js command prompt,輸入
node-red
開瀏覽器,連結 http://127.0.0.1:1880/
方法一、下載最新版本安裝即可
方法二、
檢查 Node-Red 版本:
node-red --help
輸入 npm install -g --unsafe-perm node-red