从客户端 Web 浏览器与串行端口通信。
Posted
技术标签:
【中文标题】从客户端 Web 浏览器与串行端口通信。【英文标题】:Communicate with the serial port from client web browser. 【发布时间】:2015-07-18 19:37:05 【问题描述】:在我的 Web 应用程序(sencha extjs 5)中,我有一个用户要求将数据读/写到客户端 PC 串行端口。
我知道客户端浏览器无法访问本地机器硬件,除非在本地机器上安装一些二进制文件(本机应用程序、Windows 服务等)。
几年前,我在 *** 论坛上看到过同样的问题。但是我需要知道今天使用可用技术的最佳方法是什么?
【问题讨论】:
请注意,Chrome 应用程序将于 2018 年停止使用。更多信息请点击此处:developer.chrome.com/apps/migration 【参考方案1】:使用网络串行 API。我使用它仅读取带有 RS232 串行接口的体重秤中的数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Serial</title>
</head>
<body>
<div class="serial-scale-div">
<button class="btn" id="connect-to-serial">Connect with Serial Device</button>
</div>
<button id="get-serial-messages">Get serial messages</button>
<div id="serial-messages-container">
<div class="message"></div>
</div>
<script>
"use strict";
class SerialScaleController
constructor()
this.encoder = new TextEncoder();
this.decoder = new TextDecoder();
async init()
if ('serial' in navigator)
try
const port = await navigator.serial.requestPort();
await port.open( baudRate: 9600 );
this.reader = port.readable.getReader();
let signals = await port.getSignals();
console.log(signals);
catch (err)
console.error('There was an error opening the serial port:', err);
else
console.error('Web serial doesn\'t seem to be enabled in your browser. Try enabling it by visiting:');
console.error('chrome://flags/#enable-experimental-web-platform-features');
console.error('opera://flags/#enable-experimental-web-platform-features');
console.error('edge://flags/#enable-experimental-web-platform-features');
async read()
try
const readerData = await this.reader.read();
console.log(readerData)
return this.decoder.decode(readerData.value);
catch (err)
const errorMessage = `error reading data: $err`;
console.error(errorMessage);
return errorMessage;
const serialScaleController = new SerialScaleController();
const connect = document.getElementById('connect-to-serial');
const getSerialMessages = document.getElementById('get-serial-messages');
connect.addEventListener('pointerdown', () =>
serialScaleController.init();
);
getSerialMessages.addEventListener('pointerdown', async () =>
getSerialMessage();
);
async function getSerialMessage()
document.querySelector("#serial-messages-container .message").innerText += await serialScaleController.read()
</script>
</body>
</html>
查看this demo 和this code 以获得更具描述性的示例。
您可能需要在浏览器上打开串行 API 功能。 以下是the quote from References
你可以想象,这是只有现代 Chromium 支持的 API 现在(2020 年 4 月)基于桌面浏览器,但希望支持 在不久的将来会有所改善。此时您需要启用 您的浏览器的实验性网络平台功能,只需复制和粘贴 正确的网址:
chrome://flags/#enable-experimental-web-platform-features
opera://flags/#enable-experimental-web-platform-features
edge://flags/#enable-experimental-web-platform-features
参考资料:
https://dev.to/unjavascripter/the-amazing-powers-of-the-web-web-serial-api-3ilc
https://github.com/UnJavaScripter/web-serial-example
【讨论】:
这是正确答案。它是最新的,并且在 chrome 上没有问题。不能等待它默认启用。【参考方案2】:嗯,一种方法是开发一个 chrome 应用程序。您可以使用 chrome.serial API。
https://developer.chrome.com/apps/serial
示例代码,
在你的 manifest.json 中,
"name": "Serial Sample",
"description": "Read/Write from/to serial port.",
"version": "1.0",
"manifest_version": 2,
"permissions": ["serial"],
"app":
"background":
"scripts": ["background.js"]
在你的 background.js 中,
const DEVICE_PATH = 'COM1';
const serial = chrome.serial;
var dataRecieved="";
/* Interprets an ArrayBuffer as UTF-8 encoded string data. */
var ab2str = function(buf)
var bufView = new Uint8Array(buf);
var encodedString = String.fromCharCode.apply(null, bufView);
return decodeURIComponent(escape(encodedString));
;
/* Converts a string to UTF-8 encoding in a Uint8Array; returns the array buffer. */
var str2ab = function(str)
var encodedString = unescape(encodeURIComponent(str));
var bytes = new Uint8Array(encodedString.length);
for (var i = 0; i < encodedString.length; ++i)
bytes[i] = encodedString.charCodeAt(i);
return bytes.buffer;
;
var SerialConnection = function()
this.connectionId = -1;
this.lineBuffer = "";
this.boundOnReceive = this.onReceive.bind(this);
this.boundOnReceiveError = this.onReceiveError.bind(this);
this.onConnect = new chrome.Event();
this.onReadLine = new chrome.Event();
this.onError = new chrome.Event();
;
SerialConnection.prototype.onConnectComplete = function(connectionInfo)
if (!connectionInfo)
log("Connection failed.");
return;
this.connectionId = connectionInfo.connectionId;
chrome.serial.onReceive.addListener(this.boundOnReceive);
chrome.serial.onReceiveError.addListener(this.boundOnReceiveError);
this.onConnect.dispatch();
;
SerialConnection.prototype.onReceive = function(receiveInfo)
if (receiveInfo.connectionId !== this.connectionId)
return;
this.lineBuffer += ab2str(receiveInfo.data);
var index;
while ((index = this.lineBuffer.indexOf('\n')) >= 0)
var line = this.lineBuffer.substr(0, index + 1);
this.onReadLine.dispatch(line);
this.lineBuffer = this.lineBuffer.substr(index + 1);
;
SerialConnection.prototype.onReceiveError = function(errorInfo)
if (errorInfo.connectionId === this.connectionId)
this.onError.dispatch(errorInfo.error);
;
SerialConnection.prototype.connect = function(path)
serial.connect(path, this.onConnectComplete.bind(this))
;
SerialConnection.prototype.send = function(msg)
if (this.connectionId < 0)
throw 'Invalid connection';
serial.send(this.connectionId, str2ab(msg), function() );
;
SerialConnection.prototype.disconnect = function()
if (this.connectionId < 0)
throw 'Invalid connection';
serial.disconnect(this.connectionId, function() );
;
var connection = new SerialConnection();
connection.onConnect.addListener(function()
//console.log('connected to: ' + DEVICE_PATH);
);
connection.onReadLine.addListener(function (line)
//Serial port data recieve event.
dataRecieved = dataRecieved +line;
);
connection.connect(DEVICE_PATH);
创建 chrome 应用程序以与串行端口通信后,接下来就是允许您的外部网页使用 JavaScript 与 chrome 应用程序通信。
为此在您的 manifest.json 文件中添加,
"externally_connectable":
"matches": ["*://*.example.com/*"]
这将允许您 example.com 域上的外部网页与您的 chrome 应用程序通信。
在您的网页中,
// The ID of the extension we want to talk to.
var editorExtensionId = "nboladondmajlaalmcdupihoilpcketyl";
// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId,
data: "data to pass to the chrome app" ,
function (response)
alert(response);
);
在您的 chrome 应用中,
chrome.runtime.onMessageExternal.addListener(
function (request, sender, sendResponse)
sendResponse("Send serial port data to the web page");
);
https://developer.chrome.com/apps/messaging
【讨论】:
【参考方案3】:我建立了一个网站和一个在您的浏览器中运行串行终端的简单示例。您应该将其托管在 https 服务器上。
chrome 88 中现在提供串行终端功能。
现场演示https://www.SerialTerminal.com 完整来源。 https://github.com/mmiscool/serialTerminal.com/blob/main/index.html
【讨论】:
以上是关于从客户端 Web 浏览器与串行端口通信。的主要内容,如果未能解决你的问题,请参考以下文章