快轉到主要內容

Mosquitto | 讓 JS 也支援 MQTT

·2262 字· loading · loading ·
Computer-Science MQTT Websocket
目錄
非常好用的 MQTT Server,還支援 Websocket 協定轉發!

簡介
#

MQTT 是一種通訊協定,常被用於 IoT 設備,強大的特點在於可以雙向的即時收發資訊,適合用於有即時更新資訊需求的應用情境。
其接收訊息的方式是採取對「Topic (頻道)」採取「Subscribe (訂閱)」的方式,有點像RSS的感覺;而發送訊息則是採用「Publish (發布)」,當 publish 至 topic 時,有訂閱該 topic 的 client 端即可即時的收到訊息。

MQTT Brocker
#

這種機制仰賴的是將 publish 的訊息轉發至有 subscribe 其 topic 的 client 端,因此需要一個中介來進行,該服務稱作「Brocker」。

不過這也並非是單純轉發這麼簡單,很多時候應用場景更為複雜,例如用戶的登入機制,以及限制 topics 對於用戶的 publish 或 subscribe 權限…等。

不支援 Web 端的直接應用
#

MQTT 縱使方便,但在實務開發上仍會遇到的一個阻礙:「Web 端並不支援直接連線」。
眾所周知,網頁仰賴HTTP協定,而 MQTT 協定並建立於 HTTP 之上的。

網頁上為了達到有效的雙向即時更新資料,會採取 HTTP 的升級協定「Weboscket」來進行。
伺服器與客戶端會先以 HTTP 的協定進行握手後,建立升級協定,將協定轉為wss://(即websocket)建立通訊通道,在此之後便可以透過該通道即時的收發資訊。

為了解決該阻礙,就必須要另外架設一個 websocket server 來將網頁的流量轉發至 mqtt server,並且還要另外對 websocket server 稍做修改,使其實現 mqtt 的訂閱機制,這將會是一個不小的工程。


Mosquitto
#

這是一個開源的應用,用於擔任 mqtt brocker 的角色,其命名相較蚊子的英文mosquito多了一個t

該應用強大的點在於,不僅方便對 mqtt server 設定用戶登入機制,還可以對其 topics 權限進行配置。
更厲害的是,它解決了上述提到的 websocket 流量轉發的問題,讓 websocket 與 mqtt 之間的溝通變得不再有阻礙。


安裝 Mosquitto
#

以 Ubuntu 為例:

1# Install
2sudo apt-get install mosquitto
3# Start service
4sudo service mosquitto start

這樣就完成了!
接著就可以在裝置上訪問1883port (mqtt 預設) 與 mqtt server 溝通。


設定 Mosquitto
#

/etc/mosquitto/中,可以透過修改設定檔mosquitto.conf來對其進行進階的功能設定。

使其支援 Weboscket 流量轉發
#

以原本設定檔中的 mqtt 協定只有設置以下內容:

1listener 1883
2protocol mqtt

可以加上 websocket 的支援:

1listener 9001 # port 可以自行更改
2protocol websockets #注意結尾"s"

若要使其監聽整個網段,而非僅是本地端,則指定 IP 0.0.0.0

1listener 1883 0.0.0.0
2protocol mqtt
3
4listener 9001 0.0.0.0
5protocol websockets

登入帳號列表設定
#

若要允許使用者不必登入,則可以在設定檔mosquitto.conf中加上:

1# 即便啟用該功能,依舊可以登入,並不衝突
2allow_anonymous true

也可以生成一個檔案用於存放使用者帳號密碼,首先先在/etc/mosquitto/創建一個空的文字檔「passwd(也可以自訂其他檔名或路徑)」。
之後將該檔案的路徑寫入mosquitton.conf設定檔中:

1password_file /etc/mosquitto/passwd

創建帳戶則可以使用mosquitto_passwd指令來完成,舉例創建一個名為admin的帳號:

1mosquitto_passwd -c /etc/mosquitto/passwd admin
2# 接著會要求輸入該帳號的密碼

執行完後就會發現該檔案多了一行admin:<hash>,前面為用戶名,後面為密碼(該密碼進行過雜湊運算)。

設定 Access 權限
#

一樣創建設定檔,並添加設定檔路徑至mosquitto.conf中:

1acl_file /etc/mosquitto/acl_file

/etc/mosquitto/acl_file檔案中可以這麼設定:

1topic read news/#
2topic write news/comment
3
4user admin
5topic readwrite news/#

符號「#」表示通配符,有點類似「*」,表示任意長度字元。

上方未指定 user 的區塊是作用於未登入帳戶的,topic read news/#表示可以訂閱所有news/開頭的 topics,而topic write news/comment則表示對news/comment 這個 topic 有 publish 的權限(但並沒有news/comment/的權限,mqtt 對於 topic 的斜線/敏感)。

下方指定了user admin表示是作用於用戶admin的設定,topic readwrite news/#表示該用戶對於news/開頭的所有 topics 具有 publish 及 subscribe 的權限。

還有一個更進接的 topic 比對寫法:

1pattern read client/%c/#
2pattern read user/%u/#

pattern表示比對特殊符號,在 mosquitto 中有兩個特殊符號用於該設定,分別是代表client id的「%c」;以及代表username的「%u」。
所謂username是指帳號名稱,例如上述的admin;而client id則是客戶端連接 mqtt 時可以自行設置的。

舉例來說,當用戶的 client id 為「machine123」,username 為user123時,該例子指的是該用戶可以 subscribe 所有client/machine123/開頭的 topics,以及所有user/user123/開頭的 topics。

官方文檔的用法說明:

1allow_anonymous [ true | false ]
2
3user <username>
4
5topic [read|write|readwrite|deny] <topic>
6
7pattern [read|write|readwrite|deny] <topic>
8  %c to match the client id of the client
9  %u to match the username of the client

讓 Javascript 支援 MQTT 轉接的 Websocket
#

這部份已經有套件可以使用,像是最有名的MQTT.jshttps://github.com/mqttjs/MQTT.js
或者你跟我一樣更喜歡輕便的純檔案版本:https://cdnjs.com/libraries/mqtt

For exmaple:

 1// esm 方式引入
 2import MQTT from '/Laundry/js/mqtt.js';
 3// 連接 mosquitto 監聽的 websocket port,
 4// MQTT.connect() 的第二個參數為 options,也可以不指定
 5const client = MQTT.connect('wss://mqtt.example.org:9001', {
 6  cliendId: 'user123',
 7  username: 'admin',
 8  password: 'secret',
 9});
10// 連接事件 callback
11client.on('connect', (connack)=>{});
12// subscribe 所有 topics
13client.subscribe('#');
14// 接收訊息事件 callback
15client.on('message', (topic, payload)=>{});
16
17// 事件支援 connect, reconnect, close, disconnect, offline, error, end, message, packetsend, packetreceive...

詳情請見官方文檔:https://github.com/mqttjs/MQTT.js/blob/main/README.md


References
#

Alpaca
作者
Alpaca
No one can stop my feet.

相關文章

Javascript Location Properties
·272 字· loading · loading
Computer-Science Javascript
How to get infomations of URL on javascript?
解決 Ubuntu 進入「Emergency Mode」的問題
·607 字· loading · loading
Computer-Science Ubuntu
這通常是因為磁區掛載時遇到嚴重錯誤導致的。
如何在 Docker 中訪問主機 USB ?
·540 字· loading · loading
Computer-Science Docker USB
How to run "sudo" command without typing password?
·289 字· loading · loading
Computer-Science Ubuntu
Make your username able to run "sudo" without password.
Line Flex Message 在 iPhone 上出現「錯誤 無法正常執行!」
·659 字· loading · loading
Computer-Science Line Bot IPhone

在開發 Line Bot 時,若有使用到 Flex Message,可能會踩到這個坑。

Ubuntu 使用指令連接 Wifi
·492 字· loading · loading
Computer-Science Wi-Fi

用習慣了 Desktop 版本的 Ubuntu,到 command line 卻不會用指令連接 Wifi!