需求:前端使用mqtt订阅主题和硬件设备进行通讯功能,不走后端,前端操作可以控制。从部署到对话,跟着图文一套下来你也可以学会。很简单的。后端用node,前端就用原生的js,如果要使用vue,可以看我另外一篇:还在写
1.下载EMQX
官网链接:下载 EMQX
步骤如下,我是windows系统就选windows了,看你自己是什么操作系统,根据自己的操作系统进行选择。
下载好后解压,之后进入到下载的bin目录
控制台输入`emqx start`,注意,此时控制台是没有反应的,就回你个D:\EMQX。其实已经打开了。
2.登录emqx控制台和基本配置图文讲解
控制台先别关,直接进入EMQX Dashboard,账号admin,密码:public,进行登录后会要求你自己修改密码,想改就改不想改就不改。
点击第四个图标选择监听器可以查看到mqtt的默认监听类型和端口号
点击第五个图标选择websocket客户端可以看到默认连接的主机名和端口,主题订阅等。
3.下载node-red
回到之前的控制台,输入
npm install -g node-red
下载完后输入node-red运行
点击登录node-redNode-RED,输入mqtt
选择四个节点,并且连接状态如下,连接是手动连接的,上面的hello什么的是配置的,往下看就行了
inject:输入,发消息给客户端
mqtt out:输出
matt in :输入
debug:调试
4.配置node-red
1.配置mqtt out
注意!!mqtt in 和mqtt out 配置一样就行了
Qos是决定消息质量,Qos:0,是发送端只发送一次,不管服务端收到没,1是至少发送一次,反正服务端一定能收到 1次,有可能收到2次以上,2保证服务端收到且只收到一次,值越大质量越高,qos越小,网络带宽越低。耗能越低
就修改如下俩个就行了,连接本地的1883,之后点击更新按钮,如果没有更新就点完成。
编辑inject节点,选择左边的az,选择文字列,输入内容后点击完成
最后:点击右上角部署
调试:
5.EMQX连接websocket客户端查看收到消息没
回到之前的EMQX页面
选择客户端,可以看到已经连接了一个客户端,那就是node-red部署的
在websocket客户端点击连接,之后订阅我在node-red设置的主题,从node-red发出消息,websocket也可以接收到。
6.nodejs实现主题订阅,发送消息给mqtt
npm init -y
npm install mqtt
创建index.js
const mqtt = require('mqtt')
const client = mqtt.connect('mqtt://localhost')
client.on('connect', function () {
client.subscribe('/test', function (err) {
if (!err) {
client.publish('/test', 'Hello node js')
}
})
})
client.on('message', function (topic, message) {
// message is Buffer
console.log(message.toString())
client.end()
})
注意这个hellow node js,这个是我订阅了test主题后发送的消息给mqtt服务器
7.前端实现消息发送和订阅
首先找到node_modules下的mqtt==》dist===》复制mqtt.min.js到前端的文件夹下
或者使用
<script src="https://cdn.bootcdn.net/ajax/libs/mqtt/4.1.0/mqtt.min.js"></script>
完整连接代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/mqtt/4.1.0/mqtt.min.js"></script>
</head>
<body>
<form onsubmit="return false">
<h3>WebSocket 聊天室:</h3>
<textarea
id="textarea"
style="width: 500px; height: 300px"
></textarea>
<br />
<input type="text" id="myInput" />
<button onclick="handleClick()">点击获取输入框的值发送</button>
<input
type="button"
value="清空聊天记录"
onclick="javascript:document.getElementById('myInput').value=''"
/>
<button onclick="closeWeb()">关闭客户端连接</button>
</form>
<script>
// 连接地址,有很多连接失败都是因为地址没写对
const connectUrl = `ws://localhost:8083/mqtt`;
// 客户端ID 随机数以免重复
// const clientId = `mqtt_${Math.random().toString(16).slice(3)}`;
// const clientId = `mqttx_a16dc275`;
// console.log("客户端id:" + clientId);
// 连接设置
let options = {
clean: true, // 保留会话
connectTimeout: 4000, // 超时时间
reconnectPeriod: 1000, // 重连时间间隔
// 认证信息
// clientId,
// username: "root3",
// password: "123456",
};
// 需要订阅的主题
const topic = "esp8266";
const topic1 = "/test";
// 创建客户端
// var client = mqtt.connect(connectUrl, options);
var client =mqtt.connect('ws://localhost:8083/mqtt');
// 成功连接后触发的回调
client.on("connect", () => {
$("#ts").html("在线");
console.log("已经连接成功");
// 订阅主题,这里可以订阅多个主题
client.subscribe([topic, topic1], () => {
console.log(`订阅了主题 ${[topic, topic1].join("和")}`);
});
});
// 当客户端收到一个发布过来的消息时触发回调
/**
* topic:收到的报文的topic
* message:收到的数据包的负载playload
* packet:MQTT 报文信息,其中包含 QoS、retain 等信息
*/
client.on("message", function (topic, message, packet) {
// 这里有可能拿到的数据格式是Uint8Array格式,可以直接用toString转成字符串
// let data = JSON.parse(message.toString());
console.log("获取到的数据:", message);
console.log("数据对应订阅主题:", topic);
var ta =document.getElementById("textarea")
ta.value=ta.value + "\n" + message;
// var message_packet = JSON.parse(Uint8ArrayToString(packet.payload));
// console.log("获取到的数据包:", message_packet);
// message_packet.msg;
});
// 当重新连接启动触发回调
client.on("reconnect", () => {
$("#ts").html("重连");
console.log("正在重新连接");
});
// 连接断开后触发的回调
client.on("close", function () {
$("#ts").html("离线");
console.log("已断开连接");
});
// 在收到 Broker(消息服务器) 发送过来的断开连接的报文时触发的回调,参数 packet 即为断开连接时接收到的报文。MQTT 5.0特性
client.on("disconnect", function (packet) {
console.log("从broker接收到断开连接的报文:" + packet);
});
// 客户端脱机下线触发回调
client.on("offline", function () {
console.log("您已断开连接,请检查网络");
});
// 当客户端无法成功连接时或发生解析错误时触发的回调,参数 error 为错误信息
client.on("error", (error) => {
console.log("客户端出现错误:", error);
});
//当客户端发送任何数据包时发出。这包括publish()以及MQTT用于管理订阅和连接的包
client.on("packetsend", (packet) => {
console.log("客户端已发出报文", packet);
});
//当客户端接收到任何报文时发出。这包括来自订阅主题的信息包以及MQTT用于管理订阅和连接的信息
client.on("packetreceive", (packet) => {
// 会在 client.on('message', function (topic, message, packet) {}); 之前触发
console.log("客户端接收报文", packet);
});
// 关闭客户端(断开连接)
//client.end();
// 发送信息给 topic(主题)
//client.publish(topic, '这是给topic发送的信息');
//var topic_data=[];
//topic_data.push(map)
function Uint8ArrayToString(fileData) {
var dataString = "";
for (var i = 0; i < fileData.length; i++) {
dataString += String.fromCharCode(fileData[i]);
}
return dataString;
}
function handleClick(){
var inputElement = document.getElementById("myInput");
var value = inputElement.value;
console.log(value,'获取到的值');
if(value != "" && value !=null){
// 发送信息给 topic1
client.publish(topic1, value);
var ta =document.getElementById("textarea")
// ta.value+=value;
}else{
alert("请填写内容")
}
}
function closeWeb(){
client.end();
}
</script>
</body>
</html>
效果如下:
上面俩个报错,是我浏览器版本过低,vue的扩展插件报错,不用管
这样就实现了,是不是很简单,文章到此结束,希望对你有所帮助~