赞
踩
DIY可视化整合MQTT生成UniApp源码
MQTT协议是什么?
MQTT(Message Queuing Telemetry Transport)是一种轻量级的、基于发布/订阅模式的通信协议,专门设计用于在低带宽、不稳定的网络环境下进行物联网设备之间的通信。具有以下特点(优势):
MQTT协议定义了三种角色:
总而言之,MQTT 协议由于其轻量级、灵活性和可靠性,被广泛应用于物联网设备、传感器网络、移动设备等场景,是物联网通信的重要协议之一。
安装步骤
下载
URL: https://www.emqx.io/zh/downloads?os=Windows
History URL: https://www.emqx.com/zh/downloads/broker
当前下载的是 emqx-5.3.0-windows-amd64.zip
安装
无需安装,解压 emqx-5.3.0-windows-amd64.zip 后即可使用
运行
假设 emqx-5.3.0-windows-amd64.zip 解压到以下目录:
D:\work\mqtt\emqx-5.3.2-windows-amd64
打开 CMD 窗口
运行以下命令,以下结果说明服务运行正常:
Microsoft Windows [版本 10.0.19045.3570]
(c) Microsoft Corporation。保留所有权利。
D:\work\mqtt\emqx-5.3.2-windows-amd64\bin>emqx start
EMQX_NODE__DB_ROLE [node.role]: core
EMQX_NODE__DB_BACKEND [node.db_backend]: mnesia
D:\work\mqtt\emqx-5.3.2-windows-amd64>cd bin
D:\work\mqtt\emqx-5.3.2-windows-amd64\bin>emqx_ctl status
Node 'emqx@127.0.0.1' 5.3.0 is started
访问 Web 端控制台:
http://127.0.0.1:18083/#/dashboard/overview
默认用户名密码登录:admin/public
扩展
emqx start : 后台启动 EMQX Broker;
emqx stop :关闭 EMQX Broker;
emqx restart :重启 EMQX Broker
emqx console 使用控制台启动 EMQX Broker;
emqx foreground : 使用控制台启动 EMQX Broker,与 emqx console 不同,emqx foreground 不支持输入 Erlang 命令
emqx ping :Ping EMQX Broker, 检查当前节点是否通信正常;
emqx check_conf: 检查配置文件格式是否正常,如果你修改了配置文件,推荐在启动前先执行此命令,来检查配置文件的格式是否符合要求。
emqx_ctl status:查询 EMQX 运行状态
emqx_ctl broker:查询服务器基本信息,启动时间,统计数据与性能数据
emqx_ctl broker stats:查询服务器客户端连接 (Connections)、主题 (Topics)、订阅 (Subscriptions)、路由 (Routes) 统计
emqx_ctl clients list:列出所有客户端连接
MQTT5.0桌面客户端MQTTX
MQTTX是EMQ开源的一款优雅的跨平台MQTT 5.0桌面客户端,它支持macOS、Linux和Windows系统。MQTT X的UI采用了聊天界面形式,简化了页面操作逻辑,用户可以快速创建连接,允许保存多个客户端,方便用户快速测试MQTT/MQTTS连接,以及MQTT消息的订阅和发布。
MQTT X的主要特点包括:
总的来说,MQTTX是一个功能强大、操作简便的MQTT客户端工具,适用于物联网、智能家居、移动应用等多种场景下的MQTT通信需求。
MQTTX下载地址:https://mqttx.app/zh/downloads
- <template>
- <view class="container container30157">
- <u-form :model="form" :rules="formRules" :errorType="['message', 'toast']" ref="formRef" class="flex diygw-form diygw-col-24 form-clz">
- <u-form-item class="diygw-col-24 url-clz" label="url" prop="url">
- <u-input :focus="formData.urlFocus" class="" placeholder="mqtt协议:H5使用ws/wss APP-PLUS使用wx/wxs" v-model="form.url"></u-input>
- </u-form-item>
- <u-form-item class="diygw-col-24 clientId-clz" label="clientId" prop="clientId">
- <u-input :focus="formData.clientIdFocus" class="" placeholder="clientId" v-model="form.clientId"></u-input>
- </u-form-item>
- <u-form-item class="diygw-col-24 username-clz" label="username" prop="username">
- <u-input :focus="formData.usernameFocus" class="" placeholder="username" v-model="form.username"></u-input>
- </u-form-item>
- <u-form-item class="diygw-col-24 password-clz" label="password" prop="password">
- <u-input :focus="formData.passwordFocus" class="" placeholder="password" v-model="form.password"></u-input>
- </u-form-item>
- <u-form-item class="diygw-col-24 switch-clz" label="clean" prop="switch">
- <view class="flex diygw-col-24">
- <u-switch :activeValue="1" :inactiveValue="0" @tap="changeFormSwitched" v-model="form.switched" slot="right"></u-switch>
- </view>
- </u-form-item>
- <view class="flex diygw-col-24 button-clz">
- <button @tap="navigateTo" data-type="startConnectFunction" class="diygw-btn green radius-xs flex-sub margin-xs button-button-clz">连接</button>
- <button @tap="navigateTo" data-type="endConnectFunction" class="diygw-btn green radius-xs flex-sub margin-xs button-button-clz">终止</button>
- <button @tap="navigateTo" data-type="reConnectFunction" class="diygw-btn green radius-xs flex-sub margin-xs button-button-clz">重连</button>
- </view>
- </u-form>
- <view class="flex flex-wrap diygw-col-24 flex-direction-column flex4-clz">
- <view class="flex flex-wrap diygw-col-24 justify-between green flex3-clz">
- <view class="diygw-col-0 text22-clz"> 日志消息 </view>
- <view @tap="navigateTo" data-type="cealrLogFunction" class="diygw-col-0 text2-clz"> 清空日志 </view>
- </view>
- <view v-for="(item, index) in logs" :key="index" class="flex flex-wrap diygw-col-24 flex-direction-column flex-clz">
- <view class="diygw-col-24 text-clz">
- {{ item.option + item.log }}
- </view>
- </view>
- </view>
- <view class="flex flex-wrap diygw-col-24 flex-direction-column flex2-clz">
- <view class="diygw-col-24 pink text1-clz"> 订阅消息 </view>
- <u-form :model="subscribeInfo" :rules="subscribeInfoRules" :errorType="['message', 'toast']" ref="subscribeInfoRef" class="flex diygw-form diygw-col-24 subscribeInfo-clz">
- <u-form-item class="diygw-col-24 topic-clz" label="topic" prop="topic">
- <u-input :focus="subscribeInfoData.topicFocus" class="" placeholder="topic" v-model="subscribeInfo.topic"></u-input>
- </u-form-item>
- <u-form-item class="diygw-col-24 qos-clz" label="qos" prop="qos">
- <view class="flex diygw-col-24">
- <u-number-box @change="changeSubscribeInfoQos" name="qos" v-model="subscribeInfo.qos" bgColor="#EBECEE" color="#323233" :min="0" :max="100" :step="1" />
- </view>
- </u-form-item>
- <view class="flex diygw-col-24 button3-clz">
- <button @tap="navigateTo" data-type="changeQosFunction" class="diygw-btn green radius-xs flex-sub margin-xs button3-button-clz">Qos {{ subscribeInfo.qos }}</button>
- <button @tap="navigateTo" data-type="startSubscribeFunction" class="diygw-btn green radius-xs flex-sub margin-xs button3-button-clz">订阅</button>
- <button @tap="navigateTo" data-type="endSubscribeFunction" class="diygw-btn green radius-xs flex-sub margin-xs button3-button-clz">取订</button>
- </view>
- </u-form>
- </view>
- <view class="flex flex-wrap diygw-col-24 flex-direction-column flex1-clz">
- <view class="diygw-col-24 gradual-red text3-clz"> 发送消息 </view>
- <u-form :model="publishInfo" :rules="publishInfoRules" :errorType="['message', 'toast']" ref="publishInfoRef" class="flex diygw-form diygw-col-24 publishInfo-clz">
- <u-form-item class="diygw-col-24 topic-clz" label="topic" prop="topic">
- <u-input :focus="publishInfoData.topicFocus" class="" placeholder="topic" v-model="publishInfo.topic"></u-input>
- </u-form-item>
- <u-form-item class="diygw-col-24 message-clz" label="message" prop="message">
- <u-input :focus="publishInfoData.messageFocus" class="" placeholder="message" v-model="publishInfo.message"></u-input>
- </u-form-item>
- <view class="flex diygw-col-24 button2-clz">
- <button @tap="navigateTo" data-type="publishFunction" class="diygw-btn green radius-xs flex-sub margin-xs button2-button-clz">发送</button>
- </view>
- </u-form>
- </view>
- <view class="clearfix"></view>
- </view>
- </template>
-
- <script>
- export default {
- data() {
- return {
- //用户全局信息
- userInfo: {},
- //页面传参
- globalOption: {},
- //自定义全局变量
- globalData: {},
- logs: [
- {
- option: '环境配置:',
- log: '配置成功'
- }
- ],
- publishInfoRules: {},
- form: {
- url: 'ws://127.0.0.1:8083/mqtt',
- clientId: 'App_0109',
- username: 'test',
- password: 'test',
- switched: 1
- },
- formRules: {},
- publishInfo: {
- topic: 'topic',
- message: 'message'
- },
- subscribeInfo: {
- topic: 'topic',
- qos: 1
- },
- subscribeInfoRules: {},
- formData: {
- urlFocus: false,
- clientIdFocus: false,
- usernameFocus: false,
- passwordFocus: false
- },
- subscribeInfoData: {
- topicFocus: false
- },
- publishInfoData: {
- topicFocus: false,
- messageFocus: false
- }
- };
- },
- onShow() {
- this.setCurrentPage(this);
- },
- onLoad(option) {
- this.setCurrentPage(this);
- if (option) {
- this.setData({
- globalOption: this.getOption(option)
- });
- }
-
- this.init();
- },
- onReady() {
- this.$refs.formRef?.setRules(this.formRules);
- this.$refs.subscribeInfoRef?.setRules(this.subscribeInfoRules);
- this.$refs.publishInfoRef?.setRules(this.publishInfoRules);
- },
- methods: {
- async init() {
- await this.initResetform();
- await this.initResetsubscribeInfo();
- await this.initResetpublishInfo();
- },
- // 连接 自定义方法
- async startConnectFunction(param) {
- let thiz = this;
- var _this = this;
- let opts = {
- url: this.form.url,
- clientId: this.form.clientId,
- username: this.form.username,
- password: this.form.password,
- clean: this.form.clean == 1 ? true : false
- };
- var client = await this.$mqttTool.connect(opts);
- client.on('connect', function (res) {
- _this.logs.unshift({
- option: 'mqtt:',
- log: '连接成功'
- });
- });
- client.on('reconnect', function (res) {
- _this.logs.unshift({
- option: 'mqtt:',
- log: '重新连接'
- });
- });
- client.on('error', function (res) {
- _this.logs.unshift({
- option: 'mqtt:',
- log: '连接错误'
- });
- });
- client.on('close', function (res) {
- _this.logs.unshift({
- option: 'mqtt:',
- log: '关闭成功'
- });
- });
- client.on('message', function (topic, message, buffer) {
- if (_this.isBuffer) {
- _this.logs.unshift({
- option: topic + ' buffer:',
- log: JSON.stringify(buffer)
- });
- }
- _this.logs.unshift({
- option: topic + ' message:',
- log: message.toString()
- });
- });
- },
-
- // 终止 自定义方法
- async endConnectFunction(param) {
- let thiz = this;
- var _this = this;
- this.$mqttTool.end().then((res) => {
- _this.logs.unshift({
- option: '终止:',
- log: res
- });
- });
- },
-
- // 重新连接 自定义方法
- async reConnectFunction(param) {
- let thiz = this;
- var _this = this;
- this.$mqttTool.reconnect().then((res) => {
- _this.logs.unshift({
- option: '重连:',
- log: res
- });
- });
- },
-
- // 发送消息 自定义方法
- async publishFunction(param) {
- let thiz = this;
- var _this = this;
- let opts = {
- topic: this.publishInfo.topic,
- message: this.publishInfo.message
- };
- this.$mqttTool.publish(opts).then((res) => {
- _this.logs.unshift({
- option: '发送:',
- log: res
- });
- });
- },
-
- // 订阅 自定义方法
- async startSubscribeFunction(param) {
- let thiz = this;
- if (this.subscribeInfo.topic == '') {
- uni.showToast({
- icon: 'none',
- title: '输入topic'
- });
- return;
- }
- var _this = this;
- let opts = {
- topic: this.subscribeInfo.topic,
- qos: this.subscribeInfo.qos
- };
- this.$mqttTool.subscribe(opts).then((res) => {
- _this.logs.unshift({ option: '订阅' + opts.topic + ':', log: res });
- });
- },
-
- // 取消订阅 自定义方法
- async endSubscribeFunction(param) {
- let thiz = this;
- var _this = this;
- let opts = {
- topic: this.subscribeInfo.topic
- };
- this.$mqttTool.unsubscribe(opts).then((res) => {
- _this.logs.unshift({ option: '取消订阅:', log: res });
- });
- },
-
- // 清空日志 自定义方法
- async cealrLogFunction(param) {
- let thiz = this;
- this.logs = [{ option: '环境配置:', log: '配置成功' }];
- },
-
- // 更改Qos 自定义方法
- async changeQosFunction(param) {
- let thiz = this;
- var _this = this;
- if (this.subscribeInfo.qos >= 2) {
- this.subscribeInfo.qos = 0;
- this.logs.unshift({ option: 'Qos:', log: this.subscribeInfo.qos });
- this.startSubscribe();
- } else {
- this.subscribeInfo.qos += 1;
- this.logs.unshift({ option: 'Qos:', log: this.subscribeInfo.qos });
- this.startSubscribe();
- }
- },
- changeFormSwitched(evt) {},
- initResetform() {
- this.initform = JSON.stringify(this.form);
- },
- resetForm() {
- this.form = JSON.parse(this.initform);
- },
-
- async submitForm(e) {
- this.$refs.formRef?.setRules(this.formRules);
-
- this.$nextTick(async () => {
- let valid = await this.$refs.formRef.validate();
- if (valid) {
- //保存数据
- let param = this.form;
- let header = {};
- let url = '';
- if (!url) {
- this.showToast('请先配置表单提交地址', 'none');
- return false;
- }
-
- let res = await this.$http.post(url, param, header, 'json');
-
- if (res.code == 200) {
- this.showToast(res.msg, 'success');
- } else {
- this.showModal(res.msg, '提示', false);
- }
- } else {
- console.log('验证失败');
- }
- });
- },
- changeSubscribeInfoQos(evt) {},
- initResetsubscribeInfo() {
- this.initsubscribeInfo = JSON.stringify(this.subscribeInfo);
- },
- resetSubscribeInfo() {
- this.subscribeInfo = JSON.parse(this.initsubscribeInfo);
- },
-
- async submitSubscribeInfo(e) {
- this.$refs.subscribeInfoRef?.setRules(this.subscribeInfoRules);
-
- this.$nextTick(async () => {
- let valid = await this.$refs.subscribeInfoRef.validate();
- if (valid) {
- //保存数据
- let param = this.subscribeInfo;
- let header = {};
- let url = '';
- if (!url) {
- this.showToast('请先配置表单提交地址', 'none');
- return false;
- }
-
- let res = await this.$http.post(url, param, header, 'json');
-
- if (res.code == 200) {
- this.showToast(res.msg, 'success');
- } else {
- this.showModal(res.msg, '提示', false);
- }
- } else {
- console.log('验证失败');
- }
- });
- },
- initResetpublishInfo() {
- this.initpublishInfo = JSON.stringify(this.publishInfo);
- },
- resetPublishInfo() {
- this.publishInfo = JSON.parse(this.initpublishInfo);
- },
-
- async submitPublishInfo(e) {
- this.$refs.publishInfoRef?.setRules(this.publishInfoRules);
-
- this.$nextTick(async () => {
- let valid = await this.$refs.publishInfoRef.validate();
- if (valid) {
- //保存数据
- let param = this.publishInfo;
- let header = {};
- let url = '';
- if (!url) {
- this.showToast('请先配置表单提交地址', 'none');
- return false;
- }
-
- let res = await this.$http.post(url, param, header, 'json');
-
- if (res.code == 200) {
- this.showToast(res.msg, 'success');
- } else {
- this.showModal(res.msg, '提示', false);
- }
- } else {
- console.log('验证失败');
- }
- });
- }
- }
- };
- </script>
-
- <style lang="scss" scoped>
- .button-button-clz {
- margin: 6rpx !important;
- }
- .flex4-clz {
- padding-top: 10rpx;
- padding-left: 10rpx;
- padding-bottom: 10rpx;
- padding-right: 10rpx;
- }
- .flex3-clz {
- padding-top: 10rpx;
- font-weight: bold;
- flex: 1;
- padding-left: 10rpx;
- font-size: 28rpx !important;
- padding-bottom: 10rpx;
- padding-right: 10rpx;
- }
- .flex-clz {
- margin-left: 10rpx;
- width: calc(100% - 10rpx - 10rpx) !important;
- margin-top: 10rpx;
- margin-bottom: 10rpx;
- margin-right: 10rpx;
- }
- .text-clz {
- padding-top: 10rpx;
- padding-left: 10rpx;
- padding-bottom: 10rpx;
- padding-right: 10rpx;
- }
- .flex2-clz {
- padding-top: 10rpx;
- padding-left: 10rpx;
- padding-bottom: 10rpx;
- padding-right: 10rpx;
- }
- .text1-clz {
- padding-top: 10rpx;
- font-weight: bold;
- flex: 1;
- padding-left: 10rpx;
- font-size: 28rpx !important;
- padding-bottom: 10rpx;
- padding-right: 10rpx;
- }
- .button3-button-clz {
- margin: 6rpx !important;
- }
- .flex1-clz {
- padding-top: 10rpx;
- padding-left: 10rpx;
- padding-bottom: 10rpx;
- padding-right: 10rpx;
- }
- .text3-clz {
- padding-top: 10rpx;
- font-weight: bold;
- flex: 1;
- padding-left: 10rpx;
- font-size: 28rpx !important;
- padding-bottom: 10rpx;
- padding-right: 10rpx;
- }
- .button2-button-clz {
- margin: 6rpx !important;
- }
- .container30157 {
- padding-left: 0px;
- padding-right: 0px;
- }
- .container30157 {
- }
- </style>

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。