Chromium内核浏览器(Edge、Chrome)读取串口数据
chromium内核89版本以上的浏览才支持
域名或IP访问时需要HTTPS,localhost没有限制
什么是web串行API
Web 串口 API 为网站提供了一种阅读和写入带有 JavaScript 的串行设备的方法。串行设备通过用户系统上的串行端口或仿效串行端口的可移动 USB 和蓝牙设备连接。
换句话说,Web 串行 API 允许网站与串行设备(如微控制器和 3D 打印机)通信,从而将 Web 和物理世界连接在一起。
使用网络串行 API
功能检测
检查客户端浏览器是否支持 Web 串行 API
if ("serial" in navigator) {
// The Web Serial API is supported.
}
打开串行端口
网络串行 API 按设计是异步的,这可以防止Web UI 在等待输入时造成阻塞。
// 提示用户选择一个串口
const port = await navigator.serial.requestPort();
// 获取用户之前授予网站访问权限的所有串口.
const ports = await navigator.serial.getPorts();
// 通过硬件设备的Arduino Uno USB Vendor/Product IDs等参数筛选串口
const filters = [
{ usbVendorId: 0x2341, usbProductId: 0x0043 },
{ usbVendorId: 0x2341, usbProductId: 0x0001 }
];
// Prompt user to select an Arduino Uno device.
const port = await navigator.serial.requestPort({ filters });
打开串口
// Wait for the serial port to open.
await port.open({ baudRate: 9600 });
在打开串行端口时,您还可以指定以下任何选项。这些选项是可选的,具有方便的默认值。
baudRate:波特率
dataBits:数据位(7 或 8)
stopBits:停止位(1 或 2)
parity:校验位"none"、"even"、"odd"
bufferSize:读写缓冲区大小(必须小于 16MB)
flowControl:流量控制模式(或)。"none"、"hardware"
读取串口数据
let port, reader, inputDone;
// 文本简析流
const decoder = new TextDecoderStream();
// 添加管道
inputDone = port.readable.pipeTo(decoder.writable);
// 添加转换器
reader = decoder.readable.pipeThrough(new TransformStream(new LineBreakTransformer())).getReader();
while (true) {
const { value, done } = await reader.read();
if (value) {
// do somethings
}
if (done) {//串口关闭
reader.releaseLock();
break;
}
}
lineBreakTransformer.js
// 将原本可能截断成多个字符串的内容按顺序合并一个字符串
class LineBreakTransformer {
constructor() {
// 保存流数据直到新行出现的容器
this.container = "";
}
transform(chunk, controller) {
// 将新块追加到现有块。
this.container += chunk;
// 对于每一行分段,将解析后的行发送出去。
const lines = this.container.split("\r");
this.container = lines.pop();
lines.forEach((line) => controller.enqueue(line));
}
flush(controller) {
// 当流关闭时,清除所有剩余的块。
controller.enqueue(this.container);
}
}
关闭串口
if (reader && port && inputDone) {
await reader.cancel();
await inputDone.catch(() => { });
reader = null;
inputDone = null;
await port.close();
port = null;
}
实际应用(由于没有设备,以下代码未经测试)
封装
//serial-reader.js
export default class SerialReader {
port;//串口
reader;//读取
inputDone;
constructor() {
if (!("serial" in navigator)) {
console.error('当前浏览器不支持串口');
return;
}
this.filtersSweep = [{ usbVendorId: 0x1A86, usbProductId: 0x7523 }];///串口识别码-扫码机
}
//初始化扫码机
initSweepPrinter = async () => {
let requestOptions = { filters: this.filtersSweep };
this.port = await navigator.serial.requestPort(requestOptions);
await this.port.open({
baudRate: 115200
});
const decoder = new TextDecoderStream();
this.inputDone = this.port.readable.pipeTo(decoder.writable);
this.reader = decoder.readable.pipeThrough(new TransformStream(new LineBreakTransformer())).getReader();
//alert('连接扫码机成功');
return new Promise(async (resolve, reject) => {
while (true) {
const { value, done } = await this.reader.read();
if (value) {
//console.log('扫码机数据 = ', value);
resolve(value);
}
if (done) {
this.reader.releaseLock();
break;
}
}
});
}
//断开扫码机
disconnect = async () => {
return new Promise(async (resolve, reject) => {
if (this.reader && this.port && this.inputDone) {
await this.reader.cancel();
await this.inputDone.catch(() => { });
this.reader = null;
this.inputDone = null;
await this.port.close();
this.port = null;
resolve();
}
})
}
}
调用
import SerialReader from '../serial-reader.js';
let serialReader = new SerialReader ();
//初始化扫码机
const initSweep = async () => {
try {
await serialReader.initSweepPrinter().then(value=>{console.log(value)});
} catch (e) {
console.error('扫码机读取失败', e);
}
}
//断开
function(){
serialReader.disconnect().then(() => {
alert(`断开读卡器成功`);
});
}
参考
https://web.dev/serial/
https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API

浙公网安备 33010602011771号