当前位置:   article > 正文

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

mqtt可视化

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

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

  1. 轻量级:MQTT 协议设计简单,通信开销小,适合在资源受限的设备上使用,如传感器、嵌入式设备等。
  2. 发布/订阅模式:MQTT 使用发布/订阅模式,消息的发送者称为发布者(Publisher),消息的接收者称为订阅者(Subscriber),发布者和订阅者之间通过消息代理(Broker)进行通信。
  3. 可靠性:MQTT 协议支持消息的 QoS(Quality of Service)等级,包括至多一次、至少一次和仅一次,可以根据需求选择适当的 QoS 级别来确保消息的可靠传输。
  4. 连接保持:MQTT 客户端可以保持与消息代理的长连接,即使在网络不稳定或断开的情况下,客户端也可以重新连接并恢复通信。
  5. 适应性:MQTT 可以在 TCP/IP、TLS/SSL、WebSocket 等多种网络协议上进行通信,便于在不同的网络环境中使用。
  6. 支持保留消息:MQTT支持保留消息,使得新的订阅者可以立即获取到最新消息。
  7. 跨平台:MQTT是跨平台的,可以在各种设备和操作系统上使用。

MQTT协议定义了三种角色:

  1. 发布者(Publisher):发布消息到MQTT代理(Broker)。
  2. 订阅者(Subscriber):从MQTT代理接收消息。
  3. 代理(Broker):负责接收发布者发送的消息,并按照订阅者的订阅主题进行消息转发。
  4. 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的主要特点包括:

  1. 跨平台:支持多种操作系统,包括macOS、Linux和Windows,满足不同用户的需求。
  2. 简洁的图形界面:采用聊天界面形式,使得操作更加直观和便捷。
  3. 快速创建和保存连接:用户可以轻松创建并保存多个MQTT客户端连接,方便进行不同场景下的测试。
  4. 支持多种连接方式:支持MQTT/TCP、MQTT/TLS、MQTT/WebSocket等多种连接方式,满足不同的通信需求。
  5. 优化使用体验:通过一键式的连接方式和快速复制连接功能,优化了用户的使用体验。
  6. 此外,MQTTX还提供了丰富的功能,如支持SSL/TLS加密通信、支持WebSocket连接、支持多种认证方式等,以满足不同安全需求。

总的来说,MQTTX是一个功能强大、操作简便的MQTT客户端工具,适用于物联网、智能家居、移动应用等多种场景下的MQTT通信需求。
MQTTX下载地址:https://mqttx.app/zh/downloads

  1. <template>
  2. <view class="container container30157">
  3. <u-form :model="form" :rules="formRules" :errorType="['message', 'toast']" ref="formRef" class="flex diygw-form diygw-col-24 form-clz">
  4. <u-form-item class="diygw-col-24 url-clz" label="url" prop="url">
  5. <u-input :focus="formData.urlFocus" class="" placeholder="mqtt协议:H5使用ws/wss APP-PLUS使用wx/wxs" v-model="form.url"></u-input>
  6. </u-form-item>
  7. <u-form-item class="diygw-col-24 clientId-clz" label="clientId" prop="clientId">
  8. <u-input :focus="formData.clientIdFocus" class="" placeholder="clientId" v-model="form.clientId"></u-input>
  9. </u-form-item>
  10. <u-form-item class="diygw-col-24 username-clz" label="username" prop="username">
  11. <u-input :focus="formData.usernameFocus" class="" placeholder="username" v-model="form.username"></u-input>
  12. </u-form-item>
  13. <u-form-item class="diygw-col-24 password-clz" label="password" prop="password">
  14. <u-input :focus="formData.passwordFocus" class="" placeholder="password" v-model="form.password"></u-input>
  15. </u-form-item>
  16. <u-form-item class="diygw-col-24 switch-clz" label="clean" prop="switch">
  17. <view class="flex diygw-col-24">
  18. <u-switch :activeValue="1" :inactiveValue="0" @tap="changeFormSwitched" v-model="form.switched" slot="right"></u-switch>
  19. </view>
  20. </u-form-item>
  21. <view class="flex diygw-col-24 button-clz">
  22. <button @tap="navigateTo" data-type="startConnectFunction" class="diygw-btn green radius-xs flex-sub margin-xs button-button-clz">连接</button>
  23. <button @tap="navigateTo" data-type="endConnectFunction" class="diygw-btn green radius-xs flex-sub margin-xs button-button-clz">终止</button>
  24. <button @tap="navigateTo" data-type="reConnectFunction" class="diygw-btn green radius-xs flex-sub margin-xs button-button-clz">重连</button>
  25. </view>
  26. </u-form>
  27. <view class="flex flex-wrap diygw-col-24 flex-direction-column flex4-clz">
  28. <view class="flex flex-wrap diygw-col-24 justify-between green flex3-clz">
  29. <view class="diygw-col-0 text22-clz"> 日志消息 </view>
  30. <view @tap="navigateTo" data-type="cealrLogFunction" class="diygw-col-0 text2-clz"> 清空日志 </view>
  31. </view>
  32. <view v-for="(item, index) in logs" :key="index" class="flex flex-wrap diygw-col-24 flex-direction-column flex-clz">
  33. <view class="diygw-col-24 text-clz">
  34. {{ item.option + item.log }}
  35. </view>
  36. </view>
  37. </view>
  38. <view class="flex flex-wrap diygw-col-24 flex-direction-column flex2-clz">
  39. <view class="diygw-col-24 pink text1-clz"> 订阅消息 </view>
  40. <u-form :model="subscribeInfo" :rules="subscribeInfoRules" :errorType="['message', 'toast']" ref="subscribeInfoRef" class="flex diygw-form diygw-col-24 subscribeInfo-clz">
  41. <u-form-item class="diygw-col-24 topic-clz" label="topic" prop="topic">
  42. <u-input :focus="subscribeInfoData.topicFocus" class="" placeholder="topic" v-model="subscribeInfo.topic"></u-input>
  43. </u-form-item>
  44. <u-form-item class="diygw-col-24 qos-clz" label="qos" prop="qos">
  45. <view class="flex diygw-col-24">
  46. <u-number-box @change="changeSubscribeInfoQos" name="qos" v-model="subscribeInfo.qos" bgColor="#EBECEE" color="#323233" :min="0" :max="100" :step="1" />
  47. </view>
  48. </u-form-item>
  49. <view class="flex diygw-col-24 button3-clz">
  50. <button @tap="navigateTo" data-type="changeQosFunction" class="diygw-btn green radius-xs flex-sub margin-xs button3-button-clz">Qos {{ subscribeInfo.qos }}</button>
  51. <button @tap="navigateTo" data-type="startSubscribeFunction" class="diygw-btn green radius-xs flex-sub margin-xs button3-button-clz">订阅</button>
  52. <button @tap="navigateTo" data-type="endSubscribeFunction" class="diygw-btn green radius-xs flex-sub margin-xs button3-button-clz">取订</button>
  53. </view>
  54. </u-form>
  55. </view>
  56. <view class="flex flex-wrap diygw-col-24 flex-direction-column flex1-clz">
  57. <view class="diygw-col-24 gradual-red text3-clz"> 发送消息 </view>
  58. <u-form :model="publishInfo" :rules="publishInfoRules" :errorType="['message', 'toast']" ref="publishInfoRef" class="flex diygw-form diygw-col-24 publishInfo-clz">
  59. <u-form-item class="diygw-col-24 topic-clz" label="topic" prop="topic">
  60. <u-input :focus="publishInfoData.topicFocus" class="" placeholder="topic" v-model="publishInfo.topic"></u-input>
  61. </u-form-item>
  62. <u-form-item class="diygw-col-24 message-clz" label="message" prop="message">
  63. <u-input :focus="publishInfoData.messageFocus" class="" placeholder="message" v-model="publishInfo.message"></u-input>
  64. </u-form-item>
  65. <view class="flex diygw-col-24 button2-clz">
  66. <button @tap="navigateTo" data-type="publishFunction" class="diygw-btn green radius-xs flex-sub margin-xs button2-button-clz">发送</button>
  67. </view>
  68. </u-form>
  69. </view>
  70. <view class="clearfix"></view>
  71. </view>
  72. </template>
  73. <script>
  74. export default {
  75. data() {
  76. return {
  77. //用户全局信息
  78. userInfo: {},
  79. //页面传参
  80. globalOption: {},
  81. //自定义全局变量
  82. globalData: {},
  83. logs: [
  84. {
  85. option: '环境配置:',
  86. log: '配置成功'
  87. }
  88. ],
  89. publishInfoRules: {},
  90. form: {
  91. url: 'ws://127.0.0.1:8083/mqtt',
  92. clientId: 'App_0109',
  93. username: 'test',
  94. password: 'test',
  95. switched: 1
  96. },
  97. formRules: {},
  98. publishInfo: {
  99. topic: 'topic',
  100. message: 'message'
  101. },
  102. subscribeInfo: {
  103. topic: 'topic',
  104. qos: 1
  105. },
  106. subscribeInfoRules: {},
  107. formData: {
  108. urlFocus: false,
  109. clientIdFocus: false,
  110. usernameFocus: false,
  111. passwordFocus: false
  112. },
  113. subscribeInfoData: {
  114. topicFocus: false
  115. },
  116. publishInfoData: {
  117. topicFocus: false,
  118. messageFocus: false
  119. }
  120. };
  121. },
  122. onShow() {
  123. this.setCurrentPage(this);
  124. },
  125. onLoad(option) {
  126. this.setCurrentPage(this);
  127. if (option) {
  128. this.setData({
  129. globalOption: this.getOption(option)
  130. });
  131. }
  132. this.init();
  133. },
  134. onReady() {
  135. this.$refs.formRef?.setRules(this.formRules);
  136. this.$refs.subscribeInfoRef?.setRules(this.subscribeInfoRules);
  137. this.$refs.publishInfoRef?.setRules(this.publishInfoRules);
  138. },
  139. methods: {
  140. async init() {
  141. await this.initResetform();
  142. await this.initResetsubscribeInfo();
  143. await this.initResetpublishInfo();
  144. },
  145. // 连接 自定义方法
  146. async startConnectFunction(param) {
  147. let thiz = this;
  148. var _this = this;
  149. let opts = {
  150. url: this.form.url,
  151. clientId: this.form.clientId,
  152. username: this.form.username,
  153. password: this.form.password,
  154. clean: this.form.clean == 1 ? true : false
  155. };
  156. var client = await this.$mqttTool.connect(opts);
  157. client.on('connect', function (res) {
  158. _this.logs.unshift({
  159. option: 'mqtt:',
  160. log: '连接成功'
  161. });
  162. });
  163. client.on('reconnect', function (res) {
  164. _this.logs.unshift({
  165. option: 'mqtt:',
  166. log: '重新连接'
  167. });
  168. });
  169. client.on('error', function (res) {
  170. _this.logs.unshift({
  171. option: 'mqtt:',
  172. log: '连接错误'
  173. });
  174. });
  175. client.on('close', function (res) {
  176. _this.logs.unshift({
  177. option: 'mqtt:',
  178. log: '关闭成功'
  179. });
  180. });
  181. client.on('message', function (topic, message, buffer) {
  182. if (_this.isBuffer) {
  183. _this.logs.unshift({
  184. option: topic + ' buffer:',
  185. log: JSON.stringify(buffer)
  186. });
  187. }
  188. _this.logs.unshift({
  189. option: topic + ' message:',
  190. log: message.toString()
  191. });
  192. });
  193. },
  194. // 终止 自定义方法
  195. async endConnectFunction(param) {
  196. let thiz = this;
  197. var _this = this;
  198. this.$mqttTool.end().then((res) => {
  199. _this.logs.unshift({
  200. option: '终止:',
  201. log: res
  202. });
  203. });
  204. },
  205. // 重新连接 自定义方法
  206. async reConnectFunction(param) {
  207. let thiz = this;
  208. var _this = this;
  209. this.$mqttTool.reconnect().then((res) => {
  210. _this.logs.unshift({
  211. option: '重连:',
  212. log: res
  213. });
  214. });
  215. },
  216. // 发送消息 自定义方法
  217. async publishFunction(param) {
  218. let thiz = this;
  219. var _this = this;
  220. let opts = {
  221. topic: this.publishInfo.topic,
  222. message: this.publishInfo.message
  223. };
  224. this.$mqttTool.publish(opts).then((res) => {
  225. _this.logs.unshift({
  226. option: '发送:',
  227. log: res
  228. });
  229. });
  230. },
  231. // 订阅 自定义方法
  232. async startSubscribeFunction(param) {
  233. let thiz = this;
  234. if (this.subscribeInfo.topic == '') {
  235. uni.showToast({
  236. icon: 'none',
  237. title: '输入topic'
  238. });
  239. return;
  240. }
  241. var _this = this;
  242. let opts = {
  243. topic: this.subscribeInfo.topic,
  244. qos: this.subscribeInfo.qos
  245. };
  246. this.$mqttTool.subscribe(opts).then((res) => {
  247. _this.logs.unshift({ option: '订阅' + opts.topic + ':', log: res });
  248. });
  249. },
  250. // 取消订阅 自定义方法
  251. async endSubscribeFunction(param) {
  252. let thiz = this;
  253. var _this = this;
  254. let opts = {
  255. topic: this.subscribeInfo.topic
  256. };
  257. this.$mqttTool.unsubscribe(opts).then((res) => {
  258. _this.logs.unshift({ option: '取消订阅:', log: res });
  259. });
  260. },
  261. // 清空日志 自定义方法
  262. async cealrLogFunction(param) {
  263. let thiz = this;
  264. this.logs = [{ option: '环境配置:', log: '配置成功' }];
  265. },
  266. // 更改Qos 自定义方法
  267. async changeQosFunction(param) {
  268. let thiz = this;
  269. var _this = this;
  270. if (this.subscribeInfo.qos >= 2) {
  271. this.subscribeInfo.qos = 0;
  272. this.logs.unshift({ option: 'Qos:', log: this.subscribeInfo.qos });
  273. this.startSubscribe();
  274. } else {
  275. this.subscribeInfo.qos += 1;
  276. this.logs.unshift({ option: 'Qos:', log: this.subscribeInfo.qos });
  277. this.startSubscribe();
  278. }
  279. },
  280. changeFormSwitched(evt) {},
  281. initResetform() {
  282. this.initform = JSON.stringify(this.form);
  283. },
  284. resetForm() {
  285. this.form = JSON.parse(this.initform);
  286. },
  287. async submitForm(e) {
  288. this.$refs.formRef?.setRules(this.formRules);
  289. this.$nextTick(async () => {
  290. let valid = await this.$refs.formRef.validate();
  291. if (valid) {
  292. //保存数据
  293. let param = this.form;
  294. let header = {};
  295. let url = '';
  296. if (!url) {
  297. this.showToast('请先配置表单提交地址', 'none');
  298. return false;
  299. }
  300. let res = await this.$http.post(url, param, header, 'json');
  301. if (res.code == 200) {
  302. this.showToast(res.msg, 'success');
  303. } else {
  304. this.showModal(res.msg, '提示', false);
  305. }
  306. } else {
  307. console.log('验证失败');
  308. }
  309. });
  310. },
  311. changeSubscribeInfoQos(evt) {},
  312. initResetsubscribeInfo() {
  313. this.initsubscribeInfo = JSON.stringify(this.subscribeInfo);
  314. },
  315. resetSubscribeInfo() {
  316. this.subscribeInfo = JSON.parse(this.initsubscribeInfo);
  317. },
  318. async submitSubscribeInfo(e) {
  319. this.$refs.subscribeInfoRef?.setRules(this.subscribeInfoRules);
  320. this.$nextTick(async () => {
  321. let valid = await this.$refs.subscribeInfoRef.validate();
  322. if (valid) {
  323. //保存数据
  324. let param = this.subscribeInfo;
  325. let header = {};
  326. let url = '';
  327. if (!url) {
  328. this.showToast('请先配置表单提交地址', 'none');
  329. return false;
  330. }
  331. let res = await this.$http.post(url, param, header, 'json');
  332. if (res.code == 200) {
  333. this.showToast(res.msg, 'success');
  334. } else {
  335. this.showModal(res.msg, '提示', false);
  336. }
  337. } else {
  338. console.log('验证失败');
  339. }
  340. });
  341. },
  342. initResetpublishInfo() {
  343. this.initpublishInfo = JSON.stringify(this.publishInfo);
  344. },
  345. resetPublishInfo() {
  346. this.publishInfo = JSON.parse(this.initpublishInfo);
  347. },
  348. async submitPublishInfo(e) {
  349. this.$refs.publishInfoRef?.setRules(this.publishInfoRules);
  350. this.$nextTick(async () => {
  351. let valid = await this.$refs.publishInfoRef.validate();
  352. if (valid) {
  353. //保存数据
  354. let param = this.publishInfo;
  355. let header = {};
  356. let url = '';
  357. if (!url) {
  358. this.showToast('请先配置表单提交地址', 'none');
  359. return false;
  360. }
  361. let res = await this.$http.post(url, param, header, 'json');
  362. if (res.code == 200) {
  363. this.showToast(res.msg, 'success');
  364. } else {
  365. this.showModal(res.msg, '提示', false);
  366. }
  367. } else {
  368. console.log('验证失败');
  369. }
  370. });
  371. }
  372. }
  373. };
  374. </script>
  375. <style lang="scss" scoped>
  376. .button-button-clz {
  377. margin: 6rpx !important;
  378. }
  379. .flex4-clz {
  380. padding-top: 10rpx;
  381. padding-left: 10rpx;
  382. padding-bottom: 10rpx;
  383. padding-right: 10rpx;
  384. }
  385. .flex3-clz {
  386. padding-top: 10rpx;
  387. font-weight: bold;
  388. flex: 1;
  389. padding-left: 10rpx;
  390. font-size: 28rpx !important;
  391. padding-bottom: 10rpx;
  392. padding-right: 10rpx;
  393. }
  394. .flex-clz {
  395. margin-left: 10rpx;
  396. width: calc(100% - 10rpx - 10rpx) !important;
  397. margin-top: 10rpx;
  398. margin-bottom: 10rpx;
  399. margin-right: 10rpx;
  400. }
  401. .text-clz {
  402. padding-top: 10rpx;
  403. padding-left: 10rpx;
  404. padding-bottom: 10rpx;
  405. padding-right: 10rpx;
  406. }
  407. .flex2-clz {
  408. padding-top: 10rpx;
  409. padding-left: 10rpx;
  410. padding-bottom: 10rpx;
  411. padding-right: 10rpx;
  412. }
  413. .text1-clz {
  414. padding-top: 10rpx;
  415. font-weight: bold;
  416. flex: 1;
  417. padding-left: 10rpx;
  418. font-size: 28rpx !important;
  419. padding-bottom: 10rpx;
  420. padding-right: 10rpx;
  421. }
  422. .button3-button-clz {
  423. margin: 6rpx !important;
  424. }
  425. .flex1-clz {
  426. padding-top: 10rpx;
  427. padding-left: 10rpx;
  428. padding-bottom: 10rpx;
  429. padding-right: 10rpx;
  430. }
  431. .text3-clz {
  432. padding-top: 10rpx;
  433. font-weight: bold;
  434. flex: 1;
  435. padding-left: 10rpx;
  436. font-size: 28rpx !important;
  437. padding-bottom: 10rpx;
  438. padding-right: 10rpx;
  439. }
  440. .button2-button-clz {
  441. margin: 6rpx !important;
  442. }
  443. .container30157 {
  444. padding-left: 0px;
  445. padding-right: 0px;
  446. }
  447. .container30157 {
  448. }
  449. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/824682
推荐阅读
相关标签
  

闽ICP备14008679号