Nodejs+MQTT+espjs+vue改版实现对开发板的通信

2,084 阅读5分钟

Nodejs + MQTT + vue 改版实现对开发板的通信

上一篇 《JS物联网入门》 里面的demo是采用简单的http协议去实现的单向传输指令去控制LED灯;

用http控制显得非常鸡肋:

​ 1、首先我的设备如果是连家里的WiFi,我还得知道这个设备在局域网中ip,然后在去请求对应的服务

​ 2、即便我想麻烦一点去配好了,我们的手机必须还得连上这个局域网的WiFi,才能对其进行控制

​ 以上两点:在用户体验上是非常糟糕的体验,对于从技术层面来说,也会显得很繁琐,例如:前端在网页上显示得话,还得配置这,配置那的;那有没有好一点的解决方案;答案是肯定的;现在就引出了今天的主题MQTT,其实今天不是写很多关于理论的,更多的还是从实践的方面去融合相关的理论;

一、什么是MQTT

其实这个技术,在网上有很多好的文章可供参考和解读,我这里就不做过多的赘述,其实对于我来自己的肤浅理解来看,MQTT和socket差不多,但是在应用上,我觉得MQTT就会更加的直观易懂,这个是我 从网上扒的一张图,我觉得这个逻辑还是比较清晰的

img

我通过两个例子,来说说MQTT和socket

首先socket

​ 假设A给B,C 发信息,从socket的角度来看 那么 A,B,C三个都要在一个房间内才能都看到来自A发出的信息;

那如果是MQTT的话

​ 还是上面的这个场景,如果A要给B,C发信息 ,那么业务就是 B和C 要收到A的发的信息,那么A,B都得先订阅A发出的主题,然后才能收到A发的信息,就是你只要订阅了一个主题,然后这台mqtt服务器连着的所有客户端,只要有一个发出这个主题的,那么就能收到;

在代码层面上会更加能体现这种直观

首先我们准备三个工程

1、mqtt服务端

2、开发板代码(espruino代码)

3、前端工程

二、建立MQTT服务端(Nodejs)

首先建立MQTT服务的话,我们需要使用aedes 需要安装的库

npm i aedes@0.48.1 aedes-server-factory@0.2.1

以上两个库为了避免后面使用的时候可能存在的版本问题,我这里给出了我使用的版本号进行安装

下面就看一看我的服务器代码

// 导入aedes 实例化
const Aedes = require("aedes")();
const { createServer } = require("aedes-server-factory");
const WebsocketPort = 8083;
const TcpPort = 1883;
// 连接校验
Aedes.authenticate = function (client, username, password, callback) {
    callback(null, (username === 'user' && password.toString() === '123456'));
}
// 客户端连接 事件
Aedes.on('client', function (c) {
    console.log('Client Connected: \x1b[33m' + (c ? c.id : c) + '\x1b[0m', 'to broker', Aedes.id);
});
// 客户端断开事件
Aedes.on('clientDisconnect', function (client) {
    console.log('Client Disconnected: \x1b[31m' + (client ? client.id : client) + '\x1b[0m', 'to broker', Aedes.id);
});
/* 使用 Websocket 协议传输的 Broker */
createServer(Aedes, { ws: true }).listen(WebsocketPort, function () {
  console.info("Aedes MQTT Websocket server listening on port ", WebsocketPort);
});
/* 使用 TCP 协议传输的 Broker */
createServer(Aedes).listen(TcpPort, function () {
  console.info("Aedes MQTT TCP server started and listening on port ", TcpPort);
});

以上初始化了两个端口,一个是使用websocket连接的,一个是使用TCP连接的

注意: 前端要想直接连mqtt服务端 是必须要通过webSocket进行连接的

我们运行这个文件,对外暴露两个端口,我们的服务器端就搭起来了

image-20230228131607551.png

三、开发板的代码(espruino)

​ 板子这里我们还是和之前一样,只不过我们改成MQTT协议

注意:espruino 是没有MQTT模块的,我们想使用这个模块,我们必须要按照espjs文档上的 module add命令手动下载

image-20230228135146684.png

​ 最开始我的espjs目录是这样的,这是没有下载MQTT的情况,然后我们执行espjs module add MQTT下载模块之后

image-20230228135247846.png

我们的目录就会多出一个modules目录,里面是一个MQTT.min.js文件,这样我们就下载完成了

image-20230228135402542.png

我们只需要在项目里面引用就可以 了

image-20230228135627895.png

然后连接wifi获取ip那一块地方我是换了一个函数,改成了

image-20230228135810190.png

以下是我的函数实现

// 连接mqtt服务的函数
function connectMQTTServer() {
    // mqtt服务
    var host = '192.168.1.102';
    var client = mqtt.connect({
        host:host,
        //端口
        port:1883,
        // 用户名
        username: "user",
        // 密码
        password: '123456'
    });
    //监听连接
    client.on('connect', () => {
        console.log('connected success ...');
        // 连接成功 订阅关于 topic/led 的主题
        client.subscribe('topic/led', { qos: 1 });
    });
    // 监听收到消息
    client.on('message', (topic,message) => {
        console.log('message success ...');
        // 这里收到消息 如果 主题是我订阅的 topic/led 主题的消息,我就接受
        if (topic == 'topic/led') {
            var params = message.toString();
            params = JSON.parse(params);
            // 接受传过来的状态之后 传给D4引脚灯
            digitalWrite(NodeMCU.D4, params.status);
        }
    })
}

四、前端代码(vue)

然后前端代码的实现也比较简单,加个开关即可

前端下载一个MQTT的包

npm i mqtt@3.0.0

前端代码的结构应该是这样

image-20230228141345654.png

我的组件的全部代码贴在这里

<template>
    <div>
        <el-switch v-model="value" 
            @change="change" 
            :inactive-value="1" 
            :active-value="0" 
            active-text="开启LED灯"
            inactive-text="关闭LED灯">
        </el-switch>
    </div>
</template>

<script>
import mqtt from 'mqtt/dist/mqtt';
export default {
    data() {
        return {
            value: '',
            client: null,
        }
    },
    mounted() {
        const options = {
            // MQTT 服务器的用户名
            username: 'user',
            // 密码
            password: '123456',
            keepalive: 60,
            // 端口
            port:8083,
            // 客户端id
            clientId:'mqtt_'+Math.random()
        }
        //连接
        this.client = mqtt.connect('ws://192.168.1.102', options)
        // 监听连接成功的事件
        this.client.on('connect', e => {
            console.log('连接成功', e)
        })
        //收到消息的事件
        this.client.on('message', (topic, message) => {
            console.log(topic + '返回的数据:' + message.toString())
           
        });
        // 重连事件
        this.client.on('reconnect', (error) => {
            console.log('正在重连:' + error)
        })
        // 错误事件
        this.client.on('error', (error) => {
            console.log('连接失败:' + error)
        })
    },
    methods: {
         change(val) {
            // 想MQTT 服务 发布一个关于 topic/led 的主题 改变开发板灯的状态
            this.client.publish("topic/led", JSON.stringify({ status: val }), { qos: 2, retain: true });
        },

    },
}
</script>

<style lang="scss" scoped></style>

界面上是这个效果

image.png

显示一个开关,点击开启,灯就亮,关闭灯就灭了

以上代码会我已上传至github github.com/nodewe/esp8…

五、总结

​ 1、从上面的项目中可以看出 使用MQTT协议是不是要比socket更清晰明了呢,如果我们想要收到某一类消息我们直接订阅这个主题就能收到关于这个主题的消息数据;在代码层面也很直观

​ 2、用这个去做一些小型项目我觉得还是值得一试的