1. 程式人生 > >使用JavaScript和MQTT開發物聯網應用

使用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是一個用JavaScript實現的MQTT Broker。不僅如此,mosca還增加了對資料庫,如Redis、MongoDB的支援,用來實現訊息資料的儲存。

KOA和Express
這兩者都是非常主流的Node版本的Server,簡單易用。

實戰物聯網應用

這節我們運用之前介紹的框架,自己動手完成一個簡單的物聯網應用。應用場景如圖4所示,溫度感測器用於接收溫度,並把文件通過MQTT傳送到Server端,在Server端進行業務處理,根據溫度計算出穿衣提示,通過MQTT把資料傳送到特定的Topic,App訂閱Topic獲取資料後進行展現。

這裡寫圖片描述
圖4 “穿衣提示”業務場景框架

Broker端的實現

  • 安裝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端的溫度感測器實現

  • 安裝
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硬體演示

總結

本文和大家交流了物聯網應用的一般資料鏈路、MQTT協議的架構,並基於MQTT實現了一個簡單的物聯網應用。

現在正是前端工程師的大好機會,越來越多的嵌入式裝置都開始支援JavaScript,原因是現在有很多JavaScript引擎可以把JavaScript轉換成各種平臺的底層程式碼,比較有名的有Jerryscript、Duktape等。隨著越來越多的JavaScript工程師進入嵌入式開發的領域,嵌入式應用開發也會出現前後端分離的情況(應用開發或是驅動開發),類似於Web開發的前後端分離。前端關注在應用、創意、資料鏈路、使用者體現上,而後端則關心GPIO、I2C的底層資料介面和驅動,平臺相容性等方向。

這裡寫圖片描述