使用JavaScript和MQTT開(kāi)發(fā)物聯(lián)網(wǎng)應(yīng)用示例解析
如果說(shuō)Java和C#哪個(gè)是最好的開(kāi)發(fā)語(yǔ)言,無(wú)疑會(huì)挑起程序員之間的相互怒懟,那如果說(shuō)JavaScript是動(dòng)態(tài)性最好的語(yǔ)言,相信大家都不會(huì)有太大的爭(zhēng)議。隨著越來(lái)越多的硬件平臺(tái)和開(kāi)發(fā)板開(kāi)始支持JavaScript,JavaScript在硬件端以及物聯(lián)網(wǎng)領(lǐng)域有了新的機(jī)會(huì)。
IoT應(yīng)用開(kāi)發(fā)的數(shù)據(jù)鏈路
圖1是一個(gè)智能家居物聯(lián)平臺(tái)的數(shù)據(jù)鏈路。

圖1 智能家居物聯(lián)平臺(tái)的數(shù)據(jù)鏈路
一般來(lái)說(shuō),可以把IoT應(yīng)用分為如圖所示的四層。
- client層:指的是IoT設(shè)備,可以是冰箱、空調(diào),也可以是一些溫濕度傳感器。
- gateway層:大多數(shù)場(chǎng)景中g(shù)ateway是家里的WiFi路由器,也有小部分是基于Zigbee或藍(lán)牙的網(wǎng)關(guān)設(shè)備。智能生活場(chǎng)景中的gateway數(shù)量相對(duì)于工業(yè)領(lǐng)域要少很多,在工業(yè)領(lǐng)域存在大量的邊緣計(jì)算放在gateway層進(jìn)行處理(霧計(jì)算)。
- cloud云層:這里是集中處理業(yè)務(wù)的地方。
- 應(yīng)用層:這一層是直接與用戶打交道的地方,可以是通過(guò)電腦的Web瀏覽器、手機(jī)App,也可以是有屏幕的智能設(shè)備的顯示器。隨著語(yǔ)音技術(shù)的發(fā)展,無(wú)屏設(shè)備也可以通過(guò)語(yǔ)音交互,作為一個(gè)應(yīng)用存在于物聯(lián)網(wǎng)的交互層。
物聯(lián)設(shè)備(下文統(tǒng)稱為client),可以是單個(gè)設(shè)備或多個(gè)設(shè)備組成的應(yīng)用場(chǎng)景。比如冰箱把運(yùn)行的功耗數(shù)據(jù)、庫(kù)存數(shù)據(jù)、溫度數(shù)據(jù)采集,通過(guò)gateway發(fā)送到cloud層,cloud層收集數(shù)據(jù)后進(jìn)行異常判斷,做智能模式推薦等業(yè)務(wù)處理后到application層進(jìn)行展現(xiàn)和交互。用戶可以通過(guò)冰箱的設(shè)備數(shù)據(jù)進(jìn)行模式選擇,還可以做一些與設(shè)備無(wú)關(guān)的增值服務(wù),比如聽(tīng)音樂(lè)、買(mǎi)菜等,這就是一個(gè)智能冰箱的數(shù)據(jù)鏈路。還有些client是成組智能場(chǎng)景的,比如溫濕度傳感器將數(shù)據(jù)上傳到cloud,經(jīng)過(guò)處理和加工,動(dòng)態(tài)控制家中空調(diào)的溫度,調(diào)節(jié)空氣凈化器的運(yùn)行模式等。這么描述好像沒(méi)有體現(xiàn)出cloud層的作用,那如果運(yùn)行模式是用戶預(yù)先配置好的呢?如“當(dāng)溫度超過(guò)25度,請(qǐng)幫我打開(kāi)空調(diào)”,這些業(yè)務(wù)都可以通過(guò)cloud層進(jìn)行處理。
client層的連接方式有WiFi、Bluetooth、Zigbee,而MQTT是為了讓物聯(lián)網(wǎng)設(shè)備更加互聯(lián)互通而出現(xiàn)的應(yīng)用層數(shù)據(jù)協(xié)議。
MQTT+JavaScript
MQTT是一個(gè)長(zhǎng)連接的通訊應(yīng)用層協(xié)議,最大的特點(diǎn)是數(shù)據(jù)精簡(jiǎn)、消息可靠、Publish-Subscribe模式靈活易用。MQTT已經(jīng)成為IoT傳輸?shù)臉?biāo)準(zhǔn)協(xié)議,應(yīng)用非常廣泛。
圖2中Client指的是物聯(lián)網(wǎng)設(shè)備。Client通過(guò)對(duì)Topic的訂閱和發(fā)布數(shù)據(jù)管理應(yīng)用中的數(shù)據(jù)流動(dòng),而B(niǎo)roker是MQTT應(yīng)用中用于管理Topic的角色。Server是物聯(lián)網(wǎng)應(yīng)用中的服務(wù)端,用于處理業(yè)務(wù)邏輯。
圖2 MQTT的數(shù)據(jù)鏈路圖
MQTT被廣泛使用的一個(gè)重要的原因是MQTT的生態(tài)非常完善,同時(shí)也支持JavaScript。因此圖2所示的所有鏈路和模塊,都可以通過(guò)JavaScript實(shí)現(xiàn)。
圖3 JavaScript在MQTT架構(gòu)中常用的架構(gòu)
JavaScript在MQTT架構(gòu)中常用的框架
mosca(https://github.com/mcollina/mosca)
mosca是一個(gè)用JavaScript實(shí)現(xiàn)的MQTT Broker。不僅如此,mosca還增加了對(duì)數(shù)據(jù)庫(kù),如Redis、MongoDB的支持,用來(lái)實(shí)現(xiàn)消息數(shù)據(jù)的存儲(chǔ)。
MQTT.js(https://github.com/mqttjs/MQTT.js)
MQTT.js是官網(wǎng)推薦的JavaScript實(shí)現(xiàn)的Client端。
KOA和Express
這兩者都是非常主流的Node版本的Server,簡(jiǎn)單易用。
實(shí)戰(zhàn)物聯(lián)網(wǎng)應(yīng)用
這節(jié)我們運(yùn)用之前介紹的框架,自己動(dòng)手完成一個(gè)簡(jiǎn)單的物聯(lián)網(wǎng)應(yīng)用。應(yīng)用場(chǎng)景如圖4所示,溫度傳感器用于接收溫度,并把文檔通過(guò)MQTT發(fā)送到Server端,在Server端進(jìn)行業(yè)務(wù)處理,根據(jù)溫度計(jì)算出穿衣提示,通過(guò)MQTT把數(shù)據(jù)發(fā)送到特定的Topic,App訂閱Topic獲取數(shù)據(jù)后進(jìn)行展現(xiàn)。
圖4 “穿衣提示”業(yè)務(wù)場(chǎng)景框架
Broker端的實(shí)現(xiàn)
Broker端使用mosca,參考網(wǎng)頁(yè)https://github.com/mcollina/mosca。
安裝mosca。
nmp install mosca --save
啟動(dòng)mosca。這里需要注意,如果本地沒(méi)有配置MongoDB,則需要把a(bǔ)scoltatore中的內(nèi)容全部注釋掉。
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');
}
代碼完成后,啟動(dòng)文件,本地的一個(gè)Broker就跑在localhost的1883端口上了。
Client端的溫度傳感器實(shí)現(xiàn)
Client使用MQTT.js實(shí)現(xiàn),參考網(wǎng)頁(yè)https://github.com/mqttjs/MQTT.js
安裝
npm install mqtt --save
啟動(dòng)
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();
執(zhí)行Node index后Client就啟動(dòng)了,可以看到在MQTT.connect方法中連接了上一節(jié)中啟動(dòng)的Broker地址,連接成功后,Client會(huì)輸出日志,“>>> connected”,Broker的控制臺(tái)也會(huì)輸出Client的連接信息。
這里模擬了溫度傳感器,定時(shí)3秒向/temperature的Topic中發(fā)送溫度數(shù)據(jù)。
本節(jié)的溫度器可以在電腦中使用Node方式運(yùn)行,也可以運(yùn)行在支持JavaScript的開(kāi)發(fā)板中,如RUFF、NodeMCU、Raspberry Pi,并且可以使用真實(shí)的傳感器。
Server的實(shí)現(xiàn)
Server使用MQTT.js訂閱Client發(fā)送到/temperature Topic的數(shù)據(jù)進(jìn)行處理,把處理后的數(shù)據(jù)轉(zhuǎn)譯成JSON發(fā)送到另一業(yè)務(wù)主題/tips中。
實(shí)現(xiàn)代碼如下:
'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服務(wù)器故障";
}
else if (temperature >= 50) {
data.tips = "今天天氣非常熱,建議不要穿衣服了";
}
else if (temperature >= 40) {
data.tips = "今天天氣十分的熱,建議穿短袖T恤+短褲";
}
else if (temperature >= 30) {
data.tips = "今天天氣有點(diǎn)的熱,建議穿短袖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的實(shí)現(xiàn)
Demo的App使用KOA啟動(dòng)一個(gè)Web,在Web中展現(xiàn)當(dāng)前溫度對(duì)應(yīng)的穿衣提示,通過(guò)訂閱tips獲取數(shù)據(jù)。
安裝koa
$ npm install koa
實(shí)現(xiàn)代碼
'use strict'
const Koa = require('koa');
const mqtt = require('mqtt');
const app = new Koa();
var msg = {temperature:"-",tips:""};
// response
app.use(ctx => {
ctx.body = "當(dāng)前溫度:" + 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小節(jié)
本章給出了一個(gè)簡(jiǎn)單的物聯(lián)網(wǎng)業(yè)務(wù)的業(yè)務(wù)場(chǎng)景和實(shí)現(xiàn)邏輯,其中Client也可以運(yùn)行在電腦上進(jìn)行Demo查看,或是跑在真實(shí)物聯(lián)設(shè)備或開(kāi)發(fā)版上。如圖5,筆者使用RUFF開(kāi)發(fā)板實(shí)現(xiàn)了一次。
完整Demo代碼已經(jīng)分享在github中,大家可以輸入U(xiǎn)RL下載。
https://github.com/coolnameismy/javascript-mqtt-demo-wearingTip
總結(jié)
本文和大家交流了物聯(lián)網(wǎng)應(yīng)用的一般數(shù)據(jù)鏈路、MQTT協(xié)議的架構(gòu),并基于MQTT實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的物聯(lián)網(wǎng)應(yīng)用。
現(xiàn)在正是前端工程師的大好機(jī)會(huì),越來(lái)越多的嵌入式設(shè)備都開(kāi)始支持JavaScript,原因是現(xiàn)在有很多JavaScript引擎可以把JavaScript轉(zhuǎn)換成各種平臺(tái)的底層代碼,比較有名的有Jerryscript、Duktape等。隨著越來(lái)越多的JavaScript工程師進(jìn)入嵌入式開(kāi)發(fā)的領(lǐng)域,嵌入式應(yīng)用開(kāi)發(fā)也會(huì)出現(xiàn)前后端分離的情況(應(yīng)用開(kāi)發(fā)或是驅(qū)動(dòng)開(kāi)發(fā)),類似于Web開(kāi)發(fā)的前后端分離。前端關(guān)注在應(yīng)用、創(chuàng)意、數(shù)據(jù)鏈路、用戶體現(xiàn)上,而后端則關(guān)心GPIO、I2C的底層數(shù)據(jù)接口和驅(qū)動(dòng),平臺(tái)兼容性等方向。
到此這篇關(guān)于使用JavaScript和MQTT開(kāi)發(fā)物聯(lián)網(wǎng)應(yīng)用示例解析的文章就介紹到這了,更多相關(guān)JavaScript和MQTT開(kāi)發(fā)物聯(lián)網(wǎng)應(yīng)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用js寫(xiě)了一個(gè)類似php的print_r輸出換行功能
因?yàn)閜hp的print_r比較好用同時(shí)js卻沒(méi)有這個(gè)功能于是自己就寫(xiě)了一個(gè),感興趣的你可不要錯(cuò)過(guò)了哈,希望本文對(duì)你提高知識(shí)有所幫助2013-02-02
限制textbox或textarea輸入字符長(zhǎng)度的JS代碼
textbox或textarea的輸入字符限制有很多方法,在本將為大家詳細(xì)介紹下js中時(shí)如何實(shí)現(xiàn)的,感興趣的朋友不要錯(cuò)過(guò)2013-10-10
js實(shí)現(xiàn)addClass,removeClass,hasClass的函數(shù)代碼
js實(shí)現(xiàn)addClass,removeClass,hasClass的函數(shù)代碼,需要的朋友可以參考下。2011-07-07
JavaScript中清空數(shù)組的方法總結(jié)
本文給大家總結(jié)了三種js清空數(shù)組的方法,每種方法都與眾不同,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-12-12
JS設(shè)置手機(jī)驗(yàn)證碼60s等待實(shí)現(xiàn)代碼
本文給大家分享JS設(shè)置手機(jī)驗(yàn)證碼60s等待實(shí)現(xiàn)代碼,需要的朋友參考下吧2017-06-06
利用JavaScript制作一個(gè)搞怪的兔子動(dòng)畫(huà)效果
又是一年新春之際,祝福大家兔年快樂(lè)!給大家介紹一個(gè)有趣的動(dòng)效(兼容?IE),頁(yè)面右下角有一只搞怪的兔子,鼠標(biāo)在頁(yè)面中懸停時(shí),兔子會(huì)跟著做出不同的動(dòng)作和表情,感興趣的小伙伴可以了解一下2023-01-01
JS插入排序簡(jiǎn)單理解與實(shí)現(xiàn)方法分析
這篇文章主要介紹了JS插入排序簡(jiǎn)單理解與實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了JavaScript插入排序基本原理、實(shí)現(xiàn)方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-11-11
JavaScript與DropDownList 區(qū)別分析
大家都知道,.NET中一些Web服務(wù)器控件解析并編譯,最終被渲染的時(shí)候,其實(shí)是轉(zhuǎn)化成了普通的html控件。2010-01-01

