使用JavaScript和MQTT开发物联网应用_mqtt.js 1883-CSDN博客
Excerpt 文章浏览阅读3.1w次,点赞14次,收藏98次。如果说Java和C#哪个是最好的开发语言,无疑会挑起程序员之间的相互怒怼,那如果说JavaScript是动态性最好的语言,相信大家都不会有太大的争议。随着越来越多的硬件平台和开发板开始支持JavaScript,JavaScript在硬件端以及物联网领域有了新的机会。_mqtt.js 1883
如果说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 。
1 <span>nmp</span> <span>install</span> <span>mosca</span> <span>-</span><span>-</span><span>save</span>
启动mosca。这里需要注意,如果本地没有配置MongoDB,则需要把ascoltatore中的内容全部注释掉。
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 29 30 31 32 33 <span>var</span> mosca = <span>require</span>(<span>'mosca'</span>); <span>var</span> ascoltatore = { <span>//</span>using ascoltatore <span>//</span> <span>type</span>: <span>'mongo'</span>, <span>//</span> <span>url</span>: <span>'mongodb://localhost:27017/mqtt'</span>, <span>//</span> <span>pubsubCollection</span>: <span>'ascoltatori'</span>, <span>//</span> <span>mongo</span>: {} }; <span>var</span> settings = { <span>port</span>: <span>1883</span>, <span>backend</span>: ascoltatore }; <span>var</span> server = <span>new</span> mosca.Server(settings); server.<span>on</span>(<span>'clientConnected'</span>, <span>function</span>(client) { <span>console</span>.log(<span>'client connected'</span>, client.id); }); <span>//</span> fired <span>when</span> a message <span>is</span> received server.<span>on</span>(<span>'published'</span>, <span>function</span>(packet, client) { <span>console</span>.log(<span>'Published'</span>, packet.payload); <span>//</span>{<!-- --><span>"clientId"</span>:<span>"mqttjs_02fea7b4"</span>,<span>"topic"</span>:<span>"/tips"</span>} <span>//</span> <span>console</span>.log(<span>'>>>packet'</span>, packet); <span>//</span>{<!-- --><span>"clientId"</span>:<span>"mqttjs_02fea7b4"</span>,<span>"topic"</span>:<span>"/tips"</span>} }); server.<span>on</span>(<span>'ready'</span>, setup); <span>//</span> fired <span>when</span> the mqtt server <span>is</span> ready <span>function</span> setup() { <span>console</span>.log(<span>'Mosca server is up and running'</span>); }
代码完成后,启动文件,本地的一个Broker就跑在localhost的1883端口上了。
Client端的温度传感器实现
Client使用MQTT.js实现,参考网页https://github.com/mqttjs/MQTT.js
1 <span>npm</span> <span>install</span> <span>mqtt</span> <span>-</span><span>-</span><span>save</span>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <span>var</span> mqtt = <span>require</span>(<span>'mqtt'</span>); <span>var</span> client = mqtt.connect(<span>'mqtt://localhost:1883'</span>); client.<span>on</span>(<span>'connect'</span>, <span>function</span> () { <span>console</span>.log(<span>'>>> connected'</span>) <span>//</span> client.subscribe(<span>'/tips'</span>) setInterval( <span><span>()</span>=></span>{client.publish(<span>'/temperature'</span>, <span>'30'</span>);}, <span>3000</span> ); }) client.<span>on</span>(<span>'message'</span>, <span>function</span> (topic, message) { <span>//</span> message <span>is</span> Buffer <span>console</span>.log(message.toString()) }) <span>//</span> 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中。
实现代码如下:
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 29 30 31 32 33 34 35 36 37 38 39 40 <span>'use strict'</span> <span>const</span> mqtt = <span>require</span>(<span>'mqtt'</span>); <span>var</span> client = mqtt.connect(<span>'mqtt://localhost:1883'</span>); client.on(<span>'connect'</span>, <span><span>function</span> <span>()</span> {<!-- --></span> console.log(<span>'>>> connected'</span>); client.subscribe(<span>'/temperature'</span>); }) client.on(<span>'message'</span>, <span><span>function</span> <span>(topic, message)</span> {<!-- --></span> <span>var</span> temperature = <span>parseInt</span>(message.toString()); <span>var</span> data = {temperature}; <span>if</span> (temperature >= <span>60</span>) { data.tips = <span>"热... 500服务器故障"</span>; } <span>else</span> <span>if</span> (temperature >= <span>50</span>) { data.tips = <span>"今天天气非常热,建议不要穿衣服了"</span>; } <span>else</span> <span>if</span> (temperature >= <span>40</span>) { data.tips = <span>"今天天气十分的热,建议穿短袖T恤+短裤"</span>; } <span>else</span> <span>if</span> (temperature >= <span>30</span>) { data.tips = <span>"今天天气有点的热,建议穿短袖T恤"</span>; } <span>else</span> <span>if</span> (temperature >= <span>0</span>) { data.tips = <span>"今天天气正好,可以穿上一件薄衣服"</span>; } <span>else</span> <span>if</span> (temperature >= -<span>10</span>) { data.tips = <span>"今天天气十分寒冷,棉袄可以穿上一件"</span>; } <span>else</span> { data.tips = <span>"今天天气十分十分寒冷,棉袄可以穿上二件"</span>; } client.publish(<span>'/tips'</span>, <span>JSON</span>.stringify(data)); <span>// if (temperature+1) {}</span> <span>// message is Buffer</span> console.log(<span>JSON</span>.stringify(data)); })
App的实现
Demo的App使用KOA启动一个Web,在Web中展现当前温度对应的穿衣提示,通过订阅tips获取数据。
1 <span>$ </span>npm install koa
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 29 30 31 32 33 34 35 36 <span>'use strict'</span> <span>const</span> Koa = <span>require</span>(<span>'koa'</span>); <span>const</span> mqtt = <span>require</span>(<span>'mqtt'</span>); <span>const</span> app = <span>new</span> Koa(); <span>var</span> msg = {temperature:<span>"-"</span>,tips:<span>""</span>}; <span>// response</span> app.use(ctx => { ctx.body = <span>"当前温度:"</span> + msg.temperature + <span>"度"</span> + <span>"\n"</span> + <span>'穿衣提示:'</span>+msg.tips + <span>"\n"</span> ; }); app.listen(<span>3000</span>); <span>//mqtt</span> <span>var</span> client = mqtt.connect(<span>'mqtt://localhost:1883'</span>); client.on(<span>'connect'</span>, <span><span>function</span> <span>()</span> {<!-- --></span> console.log(<span>'>>> connected'</span>); client.subscribe(<span>'/tips'</span>); }) client.on(<span>'message'</span>, <span><span>function</span> <span>(topic, message)</span> {<!-- --></span> <span>var</span> data = <span>JSON</span>.parse(message.toString()); console.log(message.toString()); console.log(data.tips); msg = data; <span>// if (temperature+1) {}</span> <span>// message is Buffer</span> <span>// let str = message.toString();</span> <span>// let data = JSON.parse(message);</span> <span>// console.log(data.tips);</span> <span>// msg = message.toString();</span> })
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的底层数据接口和驱动,平台兼容性等方向。