MQTT教學(七):使用Node.js訂閱MQTT訊息
2017/04/12 cubie 教學文件, 硬體與DIYhtml
本文將使用MQTT.js套件開發Node.js的MQTT前端應用程式。MQTT伺服器仍採用以前介紹的Mosquitto,附帶一提,有個採用Node.js開發的開放原始碼MQTT伺服器(broker)模組,叫作Mosca,能夠獨立運做,也能嵌入Node.js程式執行,有興趣的朋友請參閱Mosca的官網介紹。前端
透過MQTT.js命令行模式發布和接收MQTT主題
MQTT.js支援在命令行(終端機)中直接輸入命令,藉以發布或接收MQTT主題。若要使用命令行模式,請用全域(global)方式安裝MQTT.js:node
1jquery
npm install mqtt -gexpress
安裝後便可在命令行(終端機)輸入底下的命令,發布一則「home/yard/DHT11」主題訊息:npm
這是透過MQTTLens程式接收此MQTT訊息的畫面:json
底下這個命令則可訂閱「home/yard/DHT11」主題:app
更多命令及其說明能夠執行mqtt help,或者mqtt help ‘命令’,例如,mqtt help pub。socket
透過Node.js程式檔訂閱MQTT主題
本節將使用MQTT.js製做一個在命令行(終端機)顯示訂閱主題訊息的Node.js程式。tcp
由於下一節的程式碼將會使用到Express和Socket.io套件,所以筆者選擇在《超圖解物聯網IoT實做入門》書本的socket專案路徑中,輸入底下的命令安裝mqtt.js:
1
npm install mqtt --save
MQTT.js的程式很簡單,底下是訂閱「home/yard/DHT11」主題的Node.js程式碼,筆者將它命名為mqtt.js。
其中,創建用戶端物件並連線到伺服器的敘述,能夠省略「連線參數」物件,它預設將連接到1883埠,並且創建一個以’mqttjs_’起頭,後面跟著8個隨機16進位數字的用戶端ID:
1
var client = mqtt.connect('mqtt://192.168.1.19');
每當收到新的主題訊息時,「message」事件會自動觸發,於是在命令行(終端機)顯示收到的主題和訊息。上面的程式碼執行結果以下,你能夠使用Arduino或者MQTTLens前端發送MQTT訊息測試:
MQTT用戶端物件的subscribe(訂閱)方法的「主題」參數,能夠是字串、陣列或物件類型。若要訂閱多個主題,請將全部主題名稱寫在一個陣列裡面;底下的敘述將訂閱兩個主題:
這是用物件類型訂閱兩個主題的示範。「主題名稱」是物件的「屬性」,QoS則是「值」:
Node.js的Buffer資料類型
伴隨MQTT.js的message(訊息)事件傳入的訊息內容類型是Node.js的二進制資料,稱為Buffer。Buffer主要用於儲存文字之外的資料,例如:圖片、聲音、視訊…等等,它也能儲存文字。請在命令列(終端機)輸入下圖裡的藍色敘述,進入Node.js的REPL模式,練習創建與操做Buffer類型資料。
上面的敘述宣告了一個20位元組空間大小的Buffer類型變數,接著對它寫入一個字串資料。Node.js的字串預設用UTF-8萬國編碼,這是一種可變動長度的編碼,不一樣的字元或符號可能佔用1~4位元組。英文字的UTF-8編碼相容於ASCII編碼,每個字元佔1個位元組;一個中文字的UTF-8編碼大多佔3個位元組。因此儲存「昨日是歷史、明日是謎團。」這12個字元須要36位元組空間,超出20個位元組之外的數據會被截掉。
僅輸入變數名稱「buff」,可取出它的原始資料值(字串資料的UTF-8編碼)。我們也能在宣告Buffer變數時,直接輸入資料,它將自動預留與資料大小相同的記憶體空間,例如:
透過Socket.io即時更新MQTT訊息網頁
本單元的範例結合Express, Socket.io和MQTT.js,在網頁上顯示即時更新的MQTT訊息(溫濕度值),此範例的檔案結構和《超圖解物聯網IoT實做入門》「使用jQuery讀取並解析JSON訊息」一節(2-25頁)相同。
Node.js專案資料夾的結構以下,js資料夾裡麪包含jQuery程式庫。
底下是mqtt.js當中的socket.io程式碼,它負責把收到的MQTT主題訊息即時轉發給HTML網頁,相關說明請參閱《超圖解物聯網IoT實做入門》「使用Socket.io創建即時連線」單元(5-27頁)。
mqtt.js的完整程式碼以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var mqtt = require('mqtt');
var opt = {
port:1883,
clientId: 'nodejs'
};
var io = require("socket.io");
var express = require("express");
var app = express();
app.use(express.static('www'));
var server = app.listen(5438);
var client = mqtt.connect('tcp://192.168.1.19');
var sio = io.listen(server);
client.on('connect', function () {
console.log('已連接至MQTT伺服器');
client.subscribe("home/yard/DHT11");
});
sio.on('connection', function(socket){
client.on('message', function (topic, msg) {
console.log('收到 ' + topic + ' 主題,訊息:' + msg.toString());
socket.emit('mqtt', { 'msg': msg.toString() });
});
});
HTML和前端JavaScript程式碼請直接參考底下的index.html原始碼;在瀏覽器端解析JSON資料、使用jQuery動態更新網頁內容,請參閱《超圖解物聯網IoT實做入門》第2-23和2-25頁。讀者也能搭配第九章介紹的C3.js或D3.js程式庫,以視覺化圖表呈現動態數據。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<html>
<head>
<meta charset="utf-8">
<title>MQTT即時溫濕度</title>
</head>
<body>
<h1>MQTT即時溫濕度</h1>
<p>
溫度:<span id="temp">??</span> ° <br>
濕度:<span id="hum">??</span> %
</p>
<script src="/socket.io/socket.io.js"></script>
<script src="js/jquery-2.1.3.min.js"></script>
<script>
$(function(){
var socket = io.connect();
socket.on('mqtt', function (data) {
var json = JSON.parse(data.msg);
$("#temp").html(json.temp);
$("#hum").html(json.humid);
});
});
</script>
</body>
</html>
延伸閱讀