DIY可视化整合MQTT生成UniApp源码

简介: DIY可视化整合MQTT生成UniApp源码

DIY可视化整合MQTT生成UniApp源码

MQTT协议是什么?

MQTT(Message Queuing Telemetry Transport)是一种轻量级的、基于发布/订阅模式的通信协议,专门设计用于在低带宽、不稳定的网络环境下进行物联网设备之间的通信。具有以下特点(优势):


轻量级:MQTT 协议设计简单,通信开销小,适合在资源受限的设备上使用,如传感器、嵌入式设备等。

发布/订阅模式:MQTT 使用发布/订阅模式,消息的发送者称为发布者(Publisher),消息的接收者称为订阅者(Subscriber),发布者和订阅者之间通过消息代理(Broker)进行通信。

可靠性:MQTT 协议支持消息的 QoS(Quality of Service)等级,包括至多一次、至少一次和仅一次,可以根据需求选择适当的 QoS 级别来确保消息的可靠传输。

连接保持:MQTT 客户端可以保持与消息代理的长连接,即使在网络不稳定或断开的情况下,客户端也可以重新连接并恢复通信。

适应性:MQTT 可以在 TCP/IP、TLS/SSL、WebSocket 等多种网络协议上进行通信,便于在不同的网络环境中使用。

支持保留消息:MQTT支持保留消息,使得新的订阅者可以立即获取到最新消息。

跨平台:MQTT是跨平台的,可以在各种设备和操作系统上使用。

MQTT协议定义了三种角色:


发布者(Publisher):发布消息到MQTT代理(Broker)。

订阅者(Subscriber):从MQTT代理接收消息。

代理(Broker):负责接收发布者发送的消息,并按照订阅者的订阅主题进行消息转发。

MQTT协议通常与各种编程语言和框架都有良好的支持,使得开发者能够轻松地在各种应用场景中实现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的主要特点包括:


跨平台:支持多种操作系统,包括macOS、Linux和Windows,满足不同用户的需求。

简洁的图形界面:采用聊天界面形式,使得操作更加直观和便捷。

快速创建和保存连接:用户可以轻松创建并保存多个MQTT客户端连接,方便进行不同场景下的测试。

支持多种连接方式:支持MQTT/TCP、MQTT/TLS、MQTT/WebSocket等多种连接方式,满足不同的通信需求。

优化使用体验:通过一键式的连接方式和快速复制连接功能,优化了用户的使用体验。

此外,MQTTX还提供了丰富的功能,如支持SSL/TLS加密通信、支持WebSocket连接、支持多种认证方式等,以满足不同安全需求。

总的来说,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>



相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
28天前
|
消息中间件 存储 监控
深度写作:深入源码理解MQ长轮询优化机制
【11月更文挑战第22天】在分布式系统中,消息队列(Message Queue, MQ)扮演着至关重要的角色。MQ不仅实现了应用间的解耦,还提供了异步消息处理、流量削峰等功能。而在MQ的众多特性中,长轮询(Long Polling)机制因其能有效提升消息处理的实时性和效率,备受关注。
64 12
|
1月前
|
数据可视化 前端开发 UED
低代码可视化-Uniapp Cascader级联选择器-代码生成器
Cascader级联选择器是一种常用的UI组件,适用于从具有层级关系的数据中进行选择,如省市区选择、公司层级选择等。它通过分组多列展示选项,支持多级分类、联动选择、搜索与过滤等功能。组件具备自定义样式、禁用选项、清空选项等特性,广泛应用于电商、企业内部系统等场景。代码示例展示了其详细的实现和调用方法。
52 7
低代码可视化-Uniapp Cascader级联选择器-代码生成器
|
28天前
|
消息中间件 存储 Java
深入源码理解MQ长轮询优化机制
【11月更文挑战第22天】在分布式系统中,消息队列(MQ)作为一种重要的中间件,广泛应用于解耦、异步处理、流量削峰等场景。其中,延时消息和定时消息作为MQ的高级功能,能够进一步满足复杂的业务需求。为了实现这些功能,MQ系统需要进行一系列优化,长轮询机制便是其中的关键一环。本文将深入探讨MQ如何设计延时消息和定时消息的优化机制,特别是长轮询机制的实现原理及其在Java中的模拟实现。
34 2
|
1月前
|
小程序 前端开发 JavaScript
在线课堂+工具组件小程序uniapp移动端源码
在线课堂+工具组件小程序uniapp移动端源码
32 0
在线课堂+工具组件小程序uniapp移动端源码
|
2月前
|
数据可视化 API
低代码可视化-uniapp购物车页面-代码生成器
低代码可视化-uniapp购物车页面-代码生成器
59 1
|
2月前
|
小程序 数据可视化 API
低代码可视化-uniapp商城首页小程序-代码生成器
低代码可视化-uniapp商城首页小程序-代码生成器
33 0
|
2月前
|
JSON 数据可视化 JavaScript
低代码可视化-uniapp响应式数据data-代码生成器
低代码可视化-uniapp响应式数据data-代码生成器
46 0
|
2月前
|
数据可视化 安全 Android开发
低代码可视化-uniapp蓝牙标签打印-代码生成器
低代码可视化-uniapp蓝牙标签打印-代码生成器
81 0
|
2月前
|
移动开发 数据可视化 小程序
低代码可视化-UniApp二维码可视化-代码生成器
低代码可视化-UniApp二维码可视化-代码生成器
43 0
|
2月前
|
消息中间件 JSON Java
开发者如何使用轻量消息队列MNS
【10月更文挑战第19天】开发者如何使用轻量消息队列MNS
93 5