基于node.js中的serialport模块实现无线传感网上位机功能

半个月前的无线传感网课设上位机的实现遇到了很多困难,特写此文章给有需要的朋友一些帮助,欢迎私信探讨

文章目录

  • 前言
  • 一、node.js中的serialport模块
  • 二、express框架
  • 三、echarts实现拓扑图
  • 四、实现下行数据
  • 五、成果展示
  • 总结


前言

本文所要实现的功能以及使用到的技术栈

功能:根据课设要求,当协调器收到信息时,我要解析收到的数据,动态显示出拓扑图,当点击拓扑图节点时,显示该节点的地址以及采集的湿度和温度
技术栈node.js解决串口通信问题,串口收到的数据通过express框架上传到服务器,前端通过axios请求服务器拿取数据,前端拿到数据后通过echarts渲染拓扑图,前后端通信存在跨域问题,利用代理转发解决
所遇困难
1. 接收串口数据断断续续,零零散散(后端获取串口数据)
2.访问数据存在跨域问题(前端获取后端数据)
3.echarts拓扑图配置项陌生(数据可视化)
4.下行数据时,需要从前端向后端传输用户指令,不方便利用Post,这里使用Get查询字符串传参
5.下行数据,无法像串口助手一样按十六进制给协调器发指令,这里要对数据进行一个特殊处理


以下是本篇文章正文内容,若要源码参考,私信作者

一、node.js中的serialport模块

serialport是解决串口通信的,可以收到串口传来的数据,也可以实现下行,先来说说如何安装

npm install serialport@10.4.0

这里注意一点,serialport这个包版本很多,每个版本的使用方法都不一样,这里给出本文使用的版本号
“serialport”: “^10.4.0”
安装好后,现在就可以开始使用了,给出使用的代码

// 引入串口通信的模块
const { SerialPort } = require('serialport');//打开COM5串口 串口号 波特率 这些都是设置好的 可以查看
const serialport = new SerialPort({ path: 'COM5', baudRate: 115200,dataBits: 8, }, (err) => {if (err) {console.log('端口打开失败!');return;}console.log('端口打开成功!',serialport.isOpen);
});// 监听串口 只要串口有数据发送过来 都会执行回调函数
serialport.on('data',(data) => {//接收串口传递来的数据console.log(data.toString());
})//错误监听
serialport.on('error',function (error) {console.log('error: '+error)
})//写入  实现下行数据serialport.write('')

写到这就已经可以监听串口了,这里讲一个本人遇到的一个棘手的问题,相信大家都会碰到
就是串口传递过来的数据,会被一段一段的切分开,这样就会很难处理数据,例如: 原数据为01 3D 47 00 00 12 A4 32 33
可能我第一次接收到的就为 01 3 剩下的D 47 00 00 12 A4 32 33 会被遗留到第二次发送,这样数据就会很乱,很难处理
这里给出解决思路:可以定义一个全局数组,把每次来的数据全部压入这个数组中,然后把数组拼接,按照原始数据长度进行切割,切割出来的数据赋值给一个变量,剩下的数据接着放置在数组中,每次来的数据都压入数组内,继续切割,继续压入…循环操作
拿到数据以后进行切割,比如01 3D 47 00 00 12 A4 32 33,01代表类型,47 3D 代表路由器地址,00 00代表协调器地址, A4 12代表终端地址,32、33分别代表终端采集到的温度和湿度,所以01这条数据类型就代表,温湿度数据通过终端发送给了路由器,路由器转发给协调器
我要对数据进行切割,然后给不同的变量赋值,将这些变量通过express框架发送给前端

二、express框架

//导入express
const express = require('express');//创建express实例对象
const app = express()//编写接口
app.get('/zigbee/upo', (req, res) => {res.send({'nodes' :  [router,terminal1] ,'lines' : lines1})})//启动服务
app.listen('8888', () => {console.log('服务器启动成功!');
})

写到这后端的事情基本上就做完了,剩下的就是前端来渲染数据,难点是拓扑图,拓扑图是参考csdn上一位大佬的

三、echarts实现拓扑图

这里贴出app.main中所有的代码,包括axios请求数据,渲染拓扑图,给拓扑图注册点击事件
版本号: “echarts”: “^5.4.2”,

<template><div align="center" class="echart-block"><el-row style="padding: 0 1000px 0 1000px"><el-button @click="update1" size="medium" type="primary" round>终端1-路由-协调器</el-button><el-button @click="update2" type="success" round>终端2-协调器</el-button></el-row><div style="height: 100%" ref="graphchart"></div><el-inputtype="textarea"class="talk-textarea"v-model="message"@keyup.enter.native="enterFun"></el-input></div>
</template>
<script>
import * as echarts from 'echarts'
import axios from 'axios'
export default {data () {return {message: '',res: '',option: {},echart: null,nodes: [// symbol 默认为圆形 diamond 菱形 triangle 三角形{name: '协调器',value: [0, 0],symbol: 'circle'}],lines: []}},components: {},mounted () {this.drawChart()},methods: {async enterFun () {await axios.get(`http://localhost:8081/zigbee/message?message=${this.message}`)},async update1 () {const res = await axios.get('http://localhost:8081/zigbee/upo')console.log(res)if (res.data.lines.length === 0) {return}for (let i = 0; i < 2; i++) {this.nodes.push(res.data.nodes[i])}for (let i = 0; i < 4; i++) {this.lines.push(res.data.lines[i])}this.echart.clear()this.echart.setOption(this.option)console.log(res.data)},async update2 () {const res2 = await axios.get('http://localhost:8081/zigbee/upt')if (res2.data.lines.length === 0) {return}this.nodes.push(res2.data.nodes[0])for (let i = 0; i < 2; i++) {this.lines.push(res2.data.lines[i])}this.echart.clear()this.echart.setOption(this.option)console.log(res2.data)},drawChart () {this.echart = echarts.init(this.$refs.graphchart)this.option = {tooltip: { trigger: '1' },legend: {textStyle: { fontSize: 20 },top: '5%',bottom: '30%',left: 'center',itemWidth: 20,itemHeight: 20,data: [{ icon: 'circle', name: '协调器' },{ icon: 'diamond', name: '终端' },{ icon: 'triangle', name: '路由器' }]},title: {text: '无线传感网拓扑图',textStyle: {fontSize: 70}},polar: {},// 极坐标系的径向轴radiusAxis: {show: false},// 极坐标系的角度轴angleAxis: {type: 'value',min: 0,max: 360,show: false},series: [{name: '终端',type: 'graph',coordinateSystem: 'polar',label: {show: true,position: 'inside',fontSize: 14},// layout:'circular',symbol: 'circle',symbolSize: 50,symbolPosition: 'start',nodes: this.nodes// links: this.links},{name: '路由器',type: 'lines',coordinateSystem: 'polar',zlevel: 1,symbol: ['none', 'arrow'],symbolSize: 10,polyline: true,effect: {show: true,period: 4,smooth: true,trailLength: 0.2,symbol: 'arrow',// symbol: 'circle',color: 'rgba(55,155,255,0.5)',symbolSize: 20,loop: true},lineStyle: {normal: {color: '#1DE9B6',width: 3, // 线条宽度opacity: 0.6, // 尾迹线条透明度curveness: 0.3 // 尾迹线条曲直度}},data: this.lines},{name: '协调器',type: 'graph',coordinateSystem: 'polar',label: {show: true,position: 'inside',fontSize: 14}, // layout:'circular', symbol: 'circle',symbolSize: 50,symbolPosition: 'start'}]}this.echart.setOption(this.option)this.echart.on('click', async function (params) {console.log('myChart----click---:', params.name)const res = await axios.get('http://localhost:8081/zigbee/data')console.log(res.data)switch (params.name) {case '路由器':alert('路由器地址为' + res.data.address3)breakcase '终端1':alert('终端2地址为' +res.data.address1 +'\n' +'温度为' +res.data.tem1 +'\n' +'湿度为' +res.data.humidity1 +'\n' +'历史温度为' +res.data.tem1 +'\n' +'历史湿度为' +res.data.humidity1)breakcase '协调器':alert('协调器地址为' + '00 00')breakcase '终端2':alert('终端2地址为' +res.data.address2 +'\n' +'温度为' +res.data.tem2 +'\n' +'湿度为' +res.data.humidity2 +'\n' +'历史温度为' +res.data.historyT2 +'\n' +'历史湿度为' +res.data.historyH2)break}})}}
}
</script><style scoped>
.echart-block {height: 150vh;
}
</style>

四、实现下行数据

实现思路: 当用户在输入框内按下回车,则把用户输入的数据传递给后端,让后端发送数据给协调器,说着简单,但是难点在于数据的格式,要如何像串口调试助手一样以十六进制发送给协调器呢?

//前端发送数据给后端  由于express框架 不方便利用post方式传值,所以这里利用查询字符串的方式传递参数
async enterFun () {await axios.get(`http://localhost:8081/zigbee/message?message=${this.message}`)}
// 后端接收数据 并且处理数据 数据处理好后 通过write方法 发送给协调器
app.get('/zigbee/message', (req, res) => {//  拿get方式传递过来的参数let str = req.query.messagestrs = str.split(" ");//将一个十六进制报文转为字符数组for(let i = 0;i<strs.length;i++){strs[i] = "0x"+strs[i];}//每个字符加上0xlet buffer = Buffer.from(strs);//将数组放到buffer// 发送数据给协调器serialport.write(buffer)
})

五、成果展示

当有设备加入无线传感网时,更新拓扑图
在这里插入图片描述
用户点击拓扑图节点时,显示相关数据
在这里插入图片描述

在这里插入图片描述

总结

本课设我负责的部分是利用前后端实现上位机,实现思路和逻辑都已交代完全
由于本文设计各类知识点,笔者将自己遇到的困难都写在这儿了,若有疑问,欢迎私信沟通!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/28710.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot : ORM 框架 JPA 与连接池 Hikari

数据库方面我们选用 Mysql &#xff0c; Spring Boot 提供了直接使用 JDBC 的方式连接数据库&#xff0c;毕竟使用 JDBC 并不是很方便&#xff0c;需要我们自己写更多的代码才能使用&#xff0c;一般而言在 Spring Boot 中我们常用的 ORM 框架有 JPA 和 Mybaties &#xff0c;本…

MySQL事务与事务的隔离级别

MySQL事务与事务的隔离级别 什么事务&#xff1f;事务的特点&#xff08;ACID&#xff09;事务的隔离级别多事务运行的并发问题隔离级别repeatable read&#xff08;可重复读&#xff09;之 MVCC&#xff08;多版本并发控制&#xff09; 并发机制优化 什么事务&#xff1f; 事务…

为什么要分表和分区?

目录 &#x1f976;为什么要分表和分区&#xff1f; &#x1f976;分表 &#x1f976;Mysql分表分为垂直切分和水平切分 &#x1f976;分表的几种方式&#xff1a; &#x1f976;mysql集群 &#x1f976;利用merge存储引擎来实现分表 &#x1f976;分区 &#x1f976;什么是分…

OpenCv之图像轮廓

目录 一、图像轮廓定义 二、绘制轮廓 三、计算轮廓面积与周长 一、图像轮廓定义 图像轮廓是具有相同颜色或灰度的连续带你的曲线.轮廓在形状分析和物体的检测和识别中很有用 轮廓的作用: 用于图形分析物体的识别与检测 注意点: 为了检测的准确性&#xff0c;需要先对图像…

【Apifox】国产测试工具雄起

在开发过程中&#xff0c;我们总是避免不了进行接口的测试&#xff0c; 而相比手动敲测试代码&#xff0c;使用测试工具进行测试更为便捷&#xff0c;高效 今天发现了一个非常好用的接口测试工具Apifox 相比于Postman&#xff0c;他还拥有一个非常nb的功能&#xff0c; 在接…

springboot整合feign实现RPC调用,并通过Hystrix实现降级

目录 一、服务提供者 二、服务消费者 三、测试效果 四、开启Hystrix实现降级功能 feign/openfeign和dubbo是常用的微服务RPC框架&#xff0c;由于feigin内部已经集成ribbon&#xff0c;自带了负载均衡的功能&#xff0c;当有多个同名的服务注册到注册中心时&#xff0c;会根…

【已解决】哪些软件可以解压RAR文件?

RAR文件是我们日常生活及工作中经常用的压缩文件&#xff0c;文件压缩后可以更方便储存或者传输&#xff0c;后续要使用的时候再进行解压。 那RAR文件如何解压呢&#xff1f;哪些软件可以用来解压RAR文件&#xff1f;在这一方面还是小白的小伙伴可以来看看下面的分享。 解压任…

Cadence Allegro PCB设计88问解析(三十一) 之 Allegro 中 打印(Plot)设置

一个学习信号完整性仿真的layout工程师 在PCB进行投板时&#xff0c;往往会打印一下装备层(Assembly)&#xff0c;给贴片&#xff0c;用于核对器件的信息等。下面简单介绍Allegro中打印(Plot)设置。 1. 在Allegro的菜单下选择File命令&#xff0c;点击Plot Setup&#xff0c;会…

【自动驾驶汽车量子群粒子过滤器】用于无人驾驶汽车列车定位的量子粒子滤波研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

SpringMVC学习笔记--下篇

SpringMVC学习笔记 文章目录 SpringMVC学习笔记1、JSON1.1、什么是JSON1.2、JSON 和 JavaScript 对象互转1.3、Controller返回JSON数据1.3.1、使用Jackson工具1.3.1.1、乱码问题的代码优化1.3.1.2、集合测试1.3.1.3、输出时间对象1.3.1.4、抽取为工具类 1.3.2、使用FastJson的工…

CCF真题练习:202209-1如此编码

题目背景 某次测验后&#xff0c;顿顿老师在黑板上留下了一串数字 23333 便飘然而去。凝望着这个神秘数字&#xff0c;小 P 同学不禁陷入了沉思…… 题目描述 已知某次测验包含 n 道单项选择题&#xff0c;其中第 i 题&#xff08;1≤i≤n&#xff09;有 个选项&#xff0c;…

Android ViewGroup onDraw为什么没调用

ViewGroup&#xff0c;它本身并没有任何可画的东西&#xff0c;它是一个透明的控件&#xff0c;因些并不会触发onDraw&#xff0c;但是你现在给LinearLayout设置一个背景色&#xff0c;其实这个背景色不管你设置成什么颜色&#xff0c;系统会认为&#xff0c;这个LinearLayout上…