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