使用JavaScript和MQTT開發物聯網應用
如果說Java和C#哪個是最好的開發語言,無疑會挑起程序員之間的相互怒懟,那如果說JavaScript是動態性最好的語言,相信大家都不會有太大的爭議。隨著越來越多的硬件平臺和開發板開始支持JavaScript,JavaScript在硬件端以及物聯網領域有了新的機會。
IoT應用開發的數據鏈路
圖1是一個智能家居物聯平臺的數據鏈路。
圖1 智能家居物聯平臺的數據鏈路
一般來說,可以把IoT應用分為如圖所示的四層。
-
client層:指的是IoT設備,可以是冰箱、空調,也可以是一些溫濕度傳感器。
-
gateway層:大多數場景中gateway是家里的WiFi路由器,也有小部分是基于Zigbee或藍牙的網關設備。智能生活場景中的gateway數量相對于工業領域要少很多,在工業領域存在大量的邊緣計算放在gateway層進行處理(霧計算)。
-
cloud云層:這里是集中處理業務的地方。
-
應用層:這一層是直接與用戶打交道的地方,可以是通過電腦的Web瀏覽器、手機App,也可以是有屏幕的智能設備的顯示器。隨著語音技術的發展,無屏設備也可以通過語音交互,作為一個應用存在于物聯網的交互層。
物聯設備(下文統稱為client),可以是單個設備或多個設備組成的應用場景。比如冰箱把運行的功耗數據、庫存數據、溫度數據采集,通過gateway發送到cloud層,cloud層收集數據后進行異常判斷,做智能模式推薦等業務處理后到application層進行展現和交互。用戶可以通過冰箱的設備數據進行模式選擇,還可以做一些與設備無關的增值服務,比如聽音樂、買菜等,這就是一個智能冰箱的數據鏈路。還有些client是成組智能場景的,比如溫濕度傳感器將數據上傳到cloud,經過處理和加工,動態控制家中空調的溫度,調節空氣凈化器的運行模式等。這么描述好像沒有體現出cloud層的作用,那如果運行模式是用戶預先配置好的呢?如“當溫度超過25度,請幫我打開空調”,這些業務都可以通過cloud層進行處理。
client層的連接方式有WiFi、Bluetooth、Zigbee,而MQTT是為了讓物聯網設備更加互聯互通而出現的應用層數據協議。
MQTT+JavaScript
MQTT是一個長連接的通訊應用層協議,最大的特點是數據精簡、消息可靠、Publish-Subscribe模式靈活易用。MQTT已經成為IoT傳輸的標準協議,應用非常廣泛。
圖2中Client指的是物聯網設備。Client通過對Topic的訂閱和發布數據管理應用中的數據流動,而Broker是MQTT應用中用于管理Topic的角色。Server是物聯網應用中的服務端,用于處理業務邏輯。
圖2 MQTT的數據鏈路圖
MQTT被廣泛使用的一個重要的原因是MQTT的生態非常完善,同時也支持JavaScript。因此圖2所示的所有鏈路和模塊,都可以通過JavaScript實現。
圖3 JavaScript在MQTT架構中常用的架構
JavaScript在MQTT架構中常用的框架
mosca( https://github.com/mcollina/mosca ) mosca是一個用JavaScript實現的MQTT Broker。不僅如此,mosca還增加了對數據庫,如Redis、MongoDB的支持,用來實現消息數據的存儲。
MQTT.js( https://github.com/mqttjs/MQTT.js ) MQTT.js是官網推薦的JavaScript實現的Client端。
KOA和Express這兩者都是非常主流的Node版本的Server,簡單易用。
實戰物聯網應用
這節我們運用之前介紹的框架,自己動手完成一個簡單的物聯網應用。應用場景如圖4所示,溫度傳感器用于接收溫度,并把文檔通過MQTT發送到Server端,在Server端進行業務處理,根據溫度計算出穿衣提示,通過MQTT把數據發送到特定的Topic,App訂閱Topic獲取數據后進行展現。
圖4 “穿衣提示”業務場景框架
Broker端的實現
Broker端使用mosca,參考網頁 https://github.com/mcollina/mosca 。
- 安裝mosca。
nmp install mosca --save
- 啟動mosca。這里需要注意,如果本地沒有配置MongoDB,則需要把ascoltatore中的內容全部注釋掉。
var mosca = require('mosca');
var ascoltatore = {
//using ascoltatore
// type: 'mongo',
// url: 'mongodb://localhost:27017/mqtt',
// pubsubCollection: 'ascoltatori',
// mongo: {}
};
var settings = {
port: 1883,
backend: ascoltatore
};
var server = new mosca.Server(settings);
server.on('clientConnected', function(client) {
console.log('client connected', client.id);
});
// fired when a message is received
server.on('published', function(packet, client) {
console.log('Published', packet.payload); //{"clientId":"mqttjs_02fea7b4","topic":"/tips"}
// console.log('>>>packet', packet); //{"clientId":"mqttjs_02fea7b4","topic":"/tips"}
});
server.on('ready', setup);
// fired when the mqtt server is ready
function setup() {
console.log('Mosca server is up and running');
}
代碼完成后,啟動文件,本地的一個Broker就跑在localhost的1883端口上了。
Client端的溫度傳感器實現
Client使用MQTT.js實現,參考網頁 https://github.com/mqttjs/MQTT.js
- 安裝
npm install mqtt --save
- 啟動
var mqtt = require('mqtt');
var client = mqtt.connect('mqtt://localhost:1883');
client.on('connect', function () {
console.log('>>> connected')
// client.subscribe('/tips')
setInterval(
()=>{client.publish('/temperature', '30');},
3000
);
})
client.on('message', function (topic, message) {
// message is Buffer
console.log(message.toString())
})
// client.end();
執行Node index后Client就啟動了,可以看到在MQTT.connect方法中連接了上一節中啟動的Broker地址,連接成功后,Client會輸出日志,“>>> connected”,Broker的控制臺也會輸出Client的連接信息。
這里模擬了溫度傳感器,定時3秒向/temperature的Topic中發送溫度數據。
本節的溫度器可以在電腦中使用Node方式運行,也可以運行在支持JavaScript的開發板中,如RUFF、NodeMCU、Raspberry Pi,并且可以使用真實的傳感器。
Server的實現
Server使用MQTT.js訂閱Client發送到/temperature Topic的數據進行處理,把處理后的數據轉譯成JSON發送到另一業務主題/tips中。
實現代碼如下:
'use strict'
const mqtt = require('mqtt');
var client = mqtt.connect('mqtt://localhost:1883');
client.on('connect', function () {
console.log('>>> connected');
client.subscribe('/temperature');
})
client.on('message', function (topic, message) {
var temperature = parseInt(message.toString());
var data = {temperature};
if (temperature >= 60) {
data.tips = "熱... 500服務器故障";
}
else if (temperature >= 50) {
data.tips = "今天天氣非常熱,建議不要穿衣服了";
}
else if (temperature >= 40) {
data.tips = "今天天氣十分的熱,建議穿短袖T恤+短褲";
}
else if (temperature >= 30) {
data.tips = "今天天氣有點的熱,建議穿短袖T恤";
}
else if (temperature >= 0) {
data.tips = "今天天氣正好,可以穿上一件薄衣服";
}
else if (temperature >= -10) {
data.tips = "今天天氣十分寒冷,棉襖可以穿上一件";
}
else {
data.tips = "今天天氣十分十分寒冷,棉襖可以穿上二件";
}
client.publish('/tips', JSON.stringify(data));
// if (temperature+1) {}
// message is Buffer
console.log(JSON.stringify(data));
})
App的實現
Demo的App使用KOA啟動一個Web,在Web中展現當前溫度對應的穿衣提示,通過訂閱tips獲取數據。
- 安裝koa
$ npm install koa
- 實現代碼
'use strict'
const Koa = require('koa');
const mqtt = require('mqtt');
const app = new Koa();
var msg = {temperature:"-",tips:""};
// response
app.use(ctx => {
ctx.body = "當前溫度:" + msg.temperature + "度" + "\n" + '穿衣提示:'+msg.tips + "\n" ;
});
app.listen(3000);
//mqtt
var client = mqtt.connect('mqtt://localhost:1883');
client.on('connect', function () {
console.log('>>> connected');
client.subscribe('/tips');
})
client.on('message', function (topic, message) {
var data = JSON.parse(message.toString());
console.log(message.toString());
console.log(data.tips);
msg = data;
// if (temperature+1) {}
// message is Buffer
// let str = message.toString();
// let data = JSON.parse(message);
// console.log(data.tips);
// msg = message.toString();
})
Demo小節
本章給出了一個簡單的物聯網業務的業務場景和實現邏輯,其中Client也可以運行在電腦上進行Demo查看,或是跑在真實物聯設備或開發版上。如圖5,筆者使用RUFF開發板實現了一次。
圖5 Demo硬件演示
完整Demo代碼已經分享在github中,大家可以輸入URL下載。
https://github.com/coolnameismy/javascript-mqtt-demo-wearingTip
總結
本文和大家交流了物聯網應用的一般數據鏈路、MQTT協議的架構,并基于MQTT實現了一個簡單的物聯網應用。
現在正是前端工程師的大好機會,越來越多的嵌入式設備都開始支持JavaScript,原因是現在有很多JavaScript引擎可以把JavaScript轉換成各種平臺的底層代碼,比較有名的有Jerryscript、Duktape等。隨著越來越多的JavaScript工程師進入嵌入式開發的領域,嵌入式應用開發也會出現前后端分離的情況(應用開發或是驅動開發),類似于Web開發的前后端分離。前端關注在應用、創意、數據鏈路、用戶體現上,而后端則關心GPIO、I2C的底層數據接口和驅動,平臺兼容性等方向。
來自:http://blog.csdn.net/tangxiaoyin/article/details/73743166