浏览器通过navigator.hid读取USB称重设备数据乱码问题及解决
浏览器端读取USB称重秤数据乱码问题解决方法
问题场景
在浏览器端通过HID API连接USB称重秤,获取缓冲区数据时出现乱码,尝试了MDN提及的所有编码格式均无法解决。相关代码及现象如下:
const device = (await navigator.hid.requestDevice({ filters: [] }))?.[0] // 弹出设备选择窗口,选中设备并完成连接 await device.open() device.oninputreport = (report) => { const buffer = report.data.buffer console.log(buffer) // 输出: ArrayBuffer(5) console.log(new TextDecoder('utf-8').decode(buffer)) // 输出: �j console.log(String.fromCharCode.apply(null, new Uint8Array(buffer))) // 输出: ÿj console.log(buffer.toString()) // 输出: �j console.log(buffer.toString('hex')) // 输出: �j }
注:在Node.js中使用usb模块访问该设备时,可通过buffer.toString('hex')正常转换为十六进制字符串(如"030402005005030402005005030402005005"),但浏览器端表现不一致。
解决方案
无需直接操作ArrayBuffer,而是利用report.data自带的DataView对象解析设备返回的结构化二进制数据。以下是读取DYMO M25 USB称重秤数据的完整代码:
const device = (await navigator.hid.requestDevice({ filters: [] }))?.[0] await device.open() device.oninputreport = (report) => { const { value, unit } = parseScaleData(report.data) console.log(value, unit) } function parseScaleData (data) { const sign = data.getUint8(0) === 4 ? 1 : -1 // 4代表正值, 5代表负值, 2代表零 const unit = data.getUint8(1) === 2 ? 'g' : 'oz' // 2代表克, 11代表盎司 const value = data.getUint16(3, true) // 以小端字节序读取数值 return { value: sign * (unit === 'oz' ? value / 10 : value), unit } }
核心原因:设备返回的是二进制协议数据,并非文本编码内容,因此用文本解码器处理必然出现乱码。通过DataView的方法可以按指定字节长度、字节序读取对应位置的数值,再结合设备协议转换为实际可读的重量和单位。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

