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

news2024/11/26 18:47:12

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

文章目录

  • 前言
  • 一、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-input
      type="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)
            break

          case '终端1':
            alert(
              '终端2地址为' +
                res.data.address1 +
                '\n' +
                '温度为' +
                res.data.tem1 +
                '\n' +
                '湿度为' +
                res.data.humidity1 +
                '\n' +
                '历史温度为' +
                res.data.tem1 +
                '\n' +
                '历史湿度为' +
                res.data.humidity1
            )

            break
          case '协调器':
            alert('协调器地址为' + '00 00')
            break
          case '终端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.message
    strs = str.split(" ");//将一个十六进制报文转为字符数组
	for(let i = 0;i<strs.length;i++){
	
	  strs[i] = "0x"+strs[i];
	
	}//每个字符加上0x
	
	let buffer = Buffer.from(strs);//将数组放到buffer
		// 发送数据给协调器
	    serialport.write(buffer)
})

五、成果展示

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

在这里插入图片描述

总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【React】next+antd报错:Module not found: Can‘t resolve ‘antd/es/content‘

Antd Next手册&#xff1a;https://ant.design/docs/react/use-with-next-cn 报错场景 根据官方手册进行项目创建 yarn create next-app antd-demoyarn add antd 得到以下环境&#xff1a; EnvironmentInfoantd5.6.4next13.4.8react18.2.0 安装完依赖后&#xff0c;运行y…

java方法详解

1. 方法概述 1.1 什么是方法 方法&#xff08;method&#xff09;是将具有独立功能的代码块组织成为一个整体&#xff0c;使其具有特殊功能的代码集 注意&#xff1a; 方法必须先创建才可以使用&#xff0c;该过程称为方法定义方法创建后并不是直接运行的&#xff0c;需要手动…

日本 NFT 项目概览与特点总结

日本的 NFT 市场 日本的 NFT 市场起源于与国内动漫和娱乐偶像的合作&#xff0c;重点关注本土文化&#xff0c;文化成为日本 NFT 项目的重要基石。 关键要点&#xff1a; 日本的 NFT 产业具有三个特点&#xff1a;广泛的知识产权&#xff08;IP&#xff09;、低 FUD 水平以及…

Ka/Ks介绍和分析

什么是Ka/Ks? 在遗传学中&#xff0c;Ka/Ks表示的是两个蛋白编码基因的非同义替换率&#xff08;Ka&#xff09;和同义替换率&#xff08;Ks&#xff09;之间的比例。这个比例可以判断是否有选择压力作用于这个蛋白质编码基因。 如果你手头有两个不同物种的同一个基因的序列…

JavaWeb项目-超市订单管理系统【Day02】

密码修改 1、编写接口方法和mybatis的SQL映射文件 Mybatis配置多参数SQL语句 当我们的SQL语句中有多个参数的时候&#xff0c;需要设置每个参数名对应的接口参数&#xff0c;不然会报错&#xff1a; Parameter ‘id’ not found. Available parameters are [argl, argg, par…

【设计模式】第十二章:观察者模式详解及应用案例

系列文章 【设计模式】七大设计原则 【设计模式】第一章&#xff1a;单例模式 【设计模式】第二章&#xff1a;工厂模式 【设计模式】第三章&#xff1a;建造者模式 【设计模式】第四章&#xff1a;原型模式 【设计模式】第五章&#xff1a;适配器模式 【设计模式】第六章&…

chatGPT如何开启 Browsing 功能,实现即时联网查询?

Openai 为每一个 chatGPT Plus 用户都开放了 Browsing 和 plugins 功能。 前者可以在 ChatGPT 觉得有必要的时候&#xff08;比如你问它今天的新闻&#xff09;&#xff0c;自动联网查询&#xff0c;后者是第三方开发者开发的插件&#xff0c;数量繁多&#xff0c;可以解决各种…

Git 常用操作总结

版本控制系统&#xff08;VCS&#xff09;是管理文件和目录所做的更改的工具&#xff0c;每一次提交便记录下目录及其文件的内容&#xff0c;以及较上一版本的更改。通过这样去跟踪项目的更改过程&#xff0c;方便与他人进行协作&#xff0c;或者撤销不想要的更改以回退到此前的…

DR模式部署LVS负载均衡集群

目录 一、配置负载调度器 1.配置虚拟 IP 地址&#xff08;VIP&#xff1a;192.168.146.180&#xff09; 2.调整 proc 响应参数 3. 配置负载分配策略 ​编辑二、部署共享存储&#xff08;NFS服务器&#xff1a;192.168.146.20&#xff09; 三、配置节点服务器 1.配置虚拟…

解决vue中mapbox地图显示一半的问题

解决vue中mapbox地图显示一半的问题 问题描述&#xff1a; 在vue中创建mapbox地图&#xff0c;地图只显示一般&#xff0c;查看浏览器开发者工具。发现将canvas.mapboxgl-canvas 的position:absolute去掉就解决了 。 代码修改&#xff1a;获取到canvas.mapboxgl-canvas,并修改…

zookeeper第一课-Zookeeper特性与节点数据类型详解

1、Zookeeper特性与节点数据类型详解 ZooKeeper 是一个开源的分布式协调框架&#xff0c;是Apache Hadoop 的一个子项目&#xff0c;主要用来解决分布式集群中应用系统的一致性问题。 Zookeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来&#xff0c;构成一…

在Linux中部署ELK架构

ELK&#xff08;ElasticSearch分布式搜索引擎、Logstash数据收集处理引擎和Kibana可视化化平台&#xff09;是在大型后端架构中&#xff0c;一个标准的数据采集方案。 在公网IP为x.x.x.x的服务器上部署Elasticsearch LogstashfilebeatredisKibana架构。这种架构先通过Logstash…

高并发场景:redis+lua防重校验

大家平时在做有并发量下单的项目时&#xff0c;代码层面基本上就分为这么几个步骤&#xff1a;参数校验--->防重校验--->库存校验扣减--->下单成功--->支付。 最近公司有个商城项目说要30分钟达到1亿的并发量。当时听到突然猛了一下。真是牛逼克拉斯呀。 不过该说…

apache php mysql python 环境部署与离线安装deb包

文章目录 1.背景介绍2. 主要涉及操作2.1 安装系统&#xff1a;2.2 apache mysql php安装2.3 配置2.4 python相关库安装 3. 操作记录3.1 软件安装3.2 读取文件内容后进行文件内容抽取3.3 执行以上的sh脚本3.4 所学3.5 打包发送 4. 参考文献 1.背景介绍 使用的系统为ubuntu18.04…

密码学学习笔记(四):Authenticated Encryption - 认证加密

加密数据的最新方法是使用一种称为一体式结构的认证加密算法&#xff0c;该算法也称为有附加数据的认证加密。从之前的博客中&#xff0c;我们看到在特定的操作模式中使用的分组密码&#xff0c;如CBC、OFB、CFB、CTR&#xff0c;提供了IND-CPA安全性。 但是IND-CCA安全性呢&a…

电脑卡顿甚至崩溃?那重置系统吧

我们平时用电脑&#xff0c;最怕遇到蓝屏、死机、报错&#xff0c;等等问题。有时还会碰到些奇奇怪怪的系统问题 文章目录 问题场景&#xff1a;解决方案&#xff1a;一、重启电脑二、移除外接设备三、系统还原1、设置系统还原2、如何进行系统还原3、系统还原失败怎么办 四、卸…

有源差分探头的电压限定和检查步骤

为了使传统示波器能够显示和测试高共模电压的电路波形&#xff0c;有源差分探头对示波器测量性能延伸到了电子功率变换器、 逆变器、 电机的速度控制、 开关电源和许多应用程序的测试。 差分探头外观构成&#xff1a; A-输出线&#xff1a;连接示波器的 BNC 输出连接头和辅助性…

【操作系统】c语言--进程调度算法(FCFS和SPN)

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

Docker轻量级可视化工具Portainer

掌握Portainer的部署和使用。 Portainer 是一款轻量级的应用&#xff0c;它提供了图形化界面&#xff0c;用于方便地管理Docker环境&#xff0c;包括单机环境和集群环境。 Portainer&#xff08;https://www.portainer.io/&#xff09;是一个流行的开源Docker管理工具&#xff…

【设计模式】第八章:桥接模式详解及应用案例

系列文章 【设计模式】七大设计原则 【设计模式】第一章&#xff1a;单例模式 【设计模式】第二章&#xff1a;工厂模式 【设计模式】第三章&#xff1a;建造者模式 【设计模式】第四章&#xff1a;原型模式 【设计模式】第五章&#xff1a;适配器模式 【设计模式】第六章&…