NodeJs+WebSocket 实现串口实时通信
前言:最近这两天在研究如何实现web页面和串口间通信,在网上也查了各种资料,electron、nw或者chrome serial,发现对于我来说都太难实现了,一来可用的资料太少,二来安装东西老是出问题,算了还是放弃吧,自己用常用且最熟悉的方式来实现吧,作为一名前端码农,选用的肯定是node作为服务器了,然后网页请求方式用ajax或websocket都可以,实现方式下文都有。
先说说基本需求:硬件:usb插口的led蜂鸣器(就一个单片机),有红黄蓝三种灯,通过下发相应的指令,实现亮相应的登或者响起蜂鸣器
一. node下先跑通
1) 安装serialport
npm install serialport
2)新建server.js文件
var SerialPort = require('serialport')//Opening a Portvar serialPort = new SerialPort('COM4', {//波特率,可在设备管理器中对应端口的属性中查看baudRate : 9600, autoOpen:false})//连接串口后进行写入指令操作serialPort.open(function (err) {console.log('IsOpen:',serialPort.isOpen) console.log('err:',err)if(!err){//16进制Buffer流const buf1 = new Buffer("01050000ff008C3A","hex") //打开红灯const buf11 = new Buffer("010500000000CDCA","hex") //关闭红灯const buf2 = new Buffer("01050001f000D80A","hex") //打开黄灯const buf21 = new Buffer("0105000100009C0A","hex") //关闭黄灯const buf3 = new Buffer("01050002f000280A","hex") //打开绿灯const buf31 = new Buffer("0105000200006C0A","hex") //关闭绿灯const bufs = [buf1,buf2,buf3]// const bufs = [buf11,buf21,buf31]var i = 0eachWrite(bufs[i])function eachWrite(item) {console.log(item) serialPort.write(item, function (error, result) {i++if(i>=bufs.length)return//指令是一条一条下发的setTimeout(function () {eachWrite(bufs[i]) },40) }) } } })//指令监听serialPort.on('data',function (data) {console.log('data received: '+data) })//错误监听serialPort.on('error',function (error) {console.log('error: '+error) })//获取端口列表SerialPort.list(function (error, ports) {ports.forEach(function(port) {console.log(port.comName); console.log(port.pnpId); console.log(port.manufacturer); }); })
3)执行代码
node server.js
4)运行代码 最终结果
二. websocket方式
1) 安装nodejs-websocket
npm install nodejs-websocket
2)新建文件websocket.js
var ws=require('nodejs-websocket');var SerialPort = require('serialport')var server = ws.createServer(function (conn, res) {conn.on("text",function(str){broadcast(server,str.split(',')); server.emit('my other event', { my: 'data' }); }); conn.on("close",function(code,reason){console.log('connection closed'); })//处理错误事件信息conn.on('error',function(err){console.log('throw err',err); }) }).listen(5000);/* **指令下发 * msg:string ; eg: '01050000ff008C3A,01050001f000D80A' * server:socket server * */function broadcast(server, msg) {var recData = []; msg.map(function (item, index) {//发送数据到客户端server.connections.forEach(function (conn) {conn.sendText(item); })//16进制Buffer流const str = new Buffer(item,"hex") recData.push(str) })var i = 0eachWrite(recData[i])function eachWrite(item) {serialPort.write(item, function (error, result) {i++if(i>=recData.length)return//指令是一条一条下发的setTimeout(function () {eachWrite(recData[i]) },40) }) } }//Opening a Portvar serialPort = new SerialPort('COM4', { baudRate : 9600, autoOpen:false})//连接串口serialPort.open(function (err) {console.log('IsOpen:',serialPort.isOpen) })//指令监听serialPort.on('data',function (data) {console.log('data received: '+data) })//错误监听serialPort.on('error',function (error) {console.log('error: '+error) })//获取端口列表SerialPort.list(function (error, ports) {ports.forEach(function(port) {console.log(port.comName); console.log(port.pnpId); console.log(port.manufacturer); }); })
3)新建html文件,index.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title><style>form{margin: 30px auto;width: 35%;}</style></head><body><br><form class="form"><fieldset><legend>wobsocket 控制</legend><br><br><div><input type="button" onclick="clickDend('01050000ff008C3A,01050001f000D80A')" value="红黄灯"><input type="button" onclick="clickDend('01050001f000D80A')" value="黄灯"><input type="button" onclick="clickDend('01050002f000280A')" value="绿灯"><input type="button" onclick="clickDend('01050003f300793A')" value="蜂鸣器"><input type="button" onclick="clickDend('0105000300003DCA')" value="关闭蜂鸣器"><input type="button" onclick="clickDend('010500000000CDCA,0105000100009C0A,0105000200006C0A,0105000300003DCA')" value="关闭所有"></div><br><ul id="content"></ul><input type="text" placeholder="请输入发送的消息" class="message" id="message"/><input type="button" value="发送" id="send" class="connect"/><input type="button" value="连接" id="connect" class="connect"/></fieldset></form><script>var oUl=document.getElementById('content');var oConnect=document.getElementById('connect');var oSend=document.getElementById('send');var oInput=document.getElementById('message');var ws=null; oConnect.οnclick=function(){ws=new WebSocket('ws://localhost:5000'); ws.onopen=function(){oUl.innerHTML+="<li>客户端已连接</li>"; } ws.onmessage=function(evt){oUl.innerHTML+="<li>"+evt.data+"</li>"; } ws.onclose=function(){oUl.innerHTML+="<li>客户端已断开连接</li>"; }; ws.οnerrοr=function(evt){oUl.innerHTML+="<li>"+evt.data+"</li>"; }; }; oSend.οnclick=function(){if(ws){ ws.send(oInput.value); } }function clickDend(val){console.log(val)if(ws){// ws.send('010500000000CDCA,0105000100009C0A,0105000200006C0A,0105000300003DCA');ws.send(val); } }</script></body></html>
4)启动服务,执行代码
node server.js
5)运行页面
三. http方式
1) 安装express,cors
npm install express cors
2)新建http.js文件
var express = require('express')var cors = require('cors') //解决跨域var app = express();var port = process.env.PORT || 1124;var SerialPort = require('serialport')var serveStatic = require('serve-static');var bodyParser = require('body-parser'); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json({limit: '1mb'})); app.use('/static',serveStatic('public')); app.listen(port) app.use(cors()) app.post('/ledControl/on.do',function (req,res) {const str = req.body.dataif(setContrl(str.split(','))){ res.send({ code:100, data:'开启成功!', message:'信息'})return} res.send({ code:101, data:'开启失败!', message:'信息'}) })/* **指令下发 * msg:string ; eg: '01050000ff008C3A,01050001f000D80A' * */function setContrl(msg){return new Promise(function (resolve,reject) {let recData=[]; msg.map(function (item, index) {//16进制Buffer流const str = new Buffer(item,"hex") recData.push(str) })var i = 0eachWrite(recData[i])function eachWrite(item) {serialPort.write(item, function (error, result) {i++if(i>=recData.length){ resolve(true)return}//指令是一条一条下发的setTimeout(function () {eachWrite(recData[i]) },40) }) }//错误监听serialPort.on('error',function (error) {console.log('error: '+error) resolve(false) }) }) }//Opening a Portvar serialPort = new SerialPort('COM4', { baudRate : 9600, autoOpen:false})//连接串口serialPort.open(function (err) {console.log('IsOpen:',serialPort.isOpen) })//指令监听serialPort.on('data',function (data) {console.log('data received: '+data) })//获取端口列表SerialPort.list(function (error, ports) {ports.forEach(function(port) {console.log(port.comName); console.log(port.pnpId); console.log(port.manufacturer); }); })
3)补充上面index.html文件
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title><style>form{margin: 30px auto;width: 35%;}</style></head><body><form action=""><fieldset><legend>http控制</legend><br><br><div id="httpCtrol"><input type="button" sy-val = '01050001f000D80A' value="黄灯"><input type="button" sy-val = '01050002f000280A' value="绿灯"><input type="button" sy-val = '010500000000CDCA,0105000100009C0A,0105000200006C0A,0105000300003DCA' value="关闭所有"></div></fieldset></form><br><form class="form"><fieldset><legend>wobsocket 控制</legend><br><br><div><input type="button" onclick="clickDend('01050000ff008C3A,01050001f000D80A')" value="红黄灯"><input type="button" onclick="clickDend('01050001f000D80A')" value="黄灯"><input type="button" onclick="clickDend('01050002f000280A')" value="绿灯"><input type="button" onclick="clickDend('01050003f300793A')" value="蜂鸣器"><input type="button" onclick="clickDend('0105000300003DCA')" value="关闭蜂鸣器"><input type="button" onclick="clickDend('010500000000CDCA,0105000100009C0A,0105000200006C0A,0105000300003DCA')" value="关闭所有"></div><br><ul id="content"></ul><input type="text" placeholder="请输入发送的消息" class="message" id="message"/><input type="button" value="发送" id="send" class="connect"/><input type="button" value="连接" id="connect" class="connect"/></fieldset></form><script src="jquery.min.js"></script><script>var oUl=document.getElementById('content');var oConnect=document.getElementById('connect');var oSend=document.getElementById('send');var oInput=document.getElementById('message');var ws=null; oConnect.οnclick=function(){ws=new WebSocket('ws://localhost:5000'); ws.onopen=function(){oUl.innerHTML+="<li>客户端已连接</li>"; } ws.onmessage=function(evt){oUl.innerHTML+="<li>"+evt.data+"</li>"; } ws.onclose=function(){oUl.innerHTML+="<li>客户端已断开连接</li>"; }; ws.οnerrοr=function(evt){oUl.innerHTML+="<li>"+evt.data+"</li>"; }; }; oSend.οnclick=function(){if(ws){ ws.send(oInput.value); } }function clickDend(val){console.log(val)if(ws){// ws.send('010500000000CDCA,0105000100009C0A,0105000200006C0A,0105000300003DCA');ws.send(val); } }</script><script>$(function () {$('#httpCtrol input').on('click',function () {var $this = $(this) $.ajax({ method:'post', url:'http://localhost:1124/ledControl/on.do', data:{data:$this.attr('sy-val')}, success:function (res) {console.log(res) } }) }) })</script></body></html>
4)启动服务
node server.js