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

