这是我参与「第五届青训营 」伴学笔记创作活动的第 16 天
项目代码:Plumbiu/mqttjs
前置知识:mqtt.js、aedes(不知道 aedes 咋用的,可以看我上期的笔记如何用nodejs搭建mqtt服务 | 青训营笔记 - 掘金 (juejin.cn),这次简单介绍一下 mqtt.js)
目标:前端通过 mqtt 协议接收到来自单片机的数据。
1. 搭建一个 mqtt 服务
这里直接复制粘贴就行,其中 websocket-stream 需要手动 npm i websocket-stream 安装即可
const aedes = require('aedes')()
const server = require('net').createServer(aedes.handle)
const httpServer = require('http').createServer()
const ws = require('websocket-stream')
const port = 1883
const wsPort = 8888
server.listen(port)
ws.createServer({
server: httpServer
}, aedes.handle)
httpServer.listen(wsPort)
代码写好之后,可以 node index.js 启动
2. 使用 mqtt.fx 工具模拟
(我的版本可能比较低)
注意:mqttfx 的端口地址是上述代码常量 port 的值
3. mqtt.js使用
这里我们没有使用任何框架,只使用了原生的 HTML、CSS、JS。如果想要在框架中使用,可以参考官网:mqttjs/MQTT.js
既然采用了原生,那么就必须使用cdn了,mqtt.js
首先引入 mqtt.js
<script src="https://unpkg.com/mqtt@4.3.7/dist/mqtt.min.js"></script>
在页面的script标签书写
注意这里的地址格式,8888 为最开始代码常量 wsPort 的值
const client = mqtt.connect('ws://127.0.0.1:8888')
mqtt.js 自带的api
//当重新连接启动触发回调
client.on('reconnect', () => {})
// 连接断开后触发的回调
client.on('close', () => {})
// 客户端脱机下线触发回调
client.on('offline', () => {})
// 当客户端无法连接或出现错误时触发回调
client.on('error', (error) => {})
//成功连接后触发的回调
client.on('connect', (connack) => {})
// 接收到消息触发的回调函数
client.on('message', (topic, message, packet) => {})
如果想要订阅主题,可以使用 client.subscribe([]) 方法,数据可以写多个值,代表订阅多个主题。
如果想要向某个主题发送数据,可以使用 client.publish(topic, val, { qos: 0}, () => {console.log('发送成功')}) 方法,topic 为发布消息对应的主题,val 为发送内容, qos 代表通信质量,第四个函数代表发送成功后的回调函数。
4. 实践
我们先假设一个场景,单片机的同学会向 Water、DHT11 两个主题发送数据,格式如下(均为 json 格式):
Water 主题:
{
"value": 1900
}
DHT11主题:
{
"tem": 25,
"hum": 80
}
前端需要展示这些数据,类似下图的效果:
废话不多说,开干!
首先我们明确知道,我们前端只需要接收数据,而不用发送数据,为了简便起见,这里可以只需要使用 client.on('connect', () => {})、client.subscribe([])、client.on('message', (topic, message, packet) => {}) 三个方法。
- 先构建 HTML 架构
<div>
<span>浇水量: </span>
<span id="water">?</span>
</div>
<div>
<span>温度: </span>
<span id="tem">?</span>
</div>
<div>
<span>湿度: </span>
<span id="hum">?</span>
</div>
- 连接服务并获取DOM元素
注意这里的地址格式,8888 为最开始代码常量 wsPort 的值
const client = mqtt.connect('ws://127.0.0.1:8888')
const water = document.getElementById('water')
const tem = document.getElementById('tem')
const hum = document.getElementById('hum')
- 关键代码
首先是连接订阅部分:这段代码表示,当我们成功连接后,订阅 Water、DHT11 两个主题
client.on('connect', () => {
client.subscribe(['Water', 'DHT11'])
})
最后是接收数据部分:当单片机向我们发送数据时,就会触发此方法
topic:触发此方法的是哪个主题,也就是单片机向哪个主题发送信息了(注意,这里的 publisher 只能是单片机)
message:单片机发送过来的数据,该数据类型为 Uint8Array,所以需要 toString() 方法转换为字符串,同时我们已经事先规定好传输格式为 JSON,所以还需要使用 JSON.pare() 方法转换为 JS 对象。
client.on('message', (topic, message) => {
const msg = JSON.parse(message.toString())
if (topic === 'Water') {
water.innerText = msg.value + 'ml'
}
if (topic === 'DHT11') {
tem.innerText = msg.tem + '°C'
hum.innerText = msg.hum + '%'
}
})
- 最后测试阶段
还是使用 mqtt.fx 软件测试。
Water 主题
DHT11 主题
点击 Publish 按钮后,页面显示正常,测试成功!
5. 总结
代码还是很简单理解的,如果想要做得更好的话,可以在后端加入数据库之类的,这里不展示了