简体   繁体   English

从客户端 Web 浏览器与串行端口通信。

[英]Communicate with the serial port from client web browser.

In my web application(sencha extjs 5) I have a user requirement to read/write data to the client PC serial port.在我的 Web 应用程序(sencha extjs 5)中,我有一个用户要求将数据读/写到客户端 PC 串行端口。

I am aware of the client browser can not access local machine hardware without installing some binaries on the local machine(Native app, Windows Service, etc..).我知道客户端浏览器无法访问本地机器硬件,除非在本地机器上安装一些二进制文件(本机应用程序、Windows 服务等)。

I have seen the same question is discussed few years back in stackoverflow forums.我看到几年前在 stackoverflow 论坛中讨论过同样的问题。 But I need to know what is the best way of doing this today with the available technologies?但是我需要知道当今使用可用技术进行此操作的最佳方法是什么?

Using Web Serial API.使用 Web 串行 API。 I am using this to ONLY read the data from my Weight Scale with RS232 Serial Interface我使用它仅从带有 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>

Checkout this demo and this code for a more descriptive example.查看此演示此代码以获得更具描述性的示例。

You might need to turn on the Serial API feature on your browser.您可能需要在浏览器上打开串行 API 功能。 Following is the quote from References以下是参考文献的引用

As you can imagine, this is API is only supported by modern Chromium based desktop browsers right now (April 2020) but hopefully support will improve in the near future.可以想象,目前(2020 年 4 月)仅基于现代 Chromium 的桌面浏览器支持此 API,但希望在不久的将来支持会得到改善。 At this moment you need to enable your browser's Experimental Web Platform Features, just copy and paste the right URL:此时您需要启用浏览器的实验性 Web 平台功能,只需复制并粘贴正确的 URL:

chrome://flags/#enable-experimental-web-platform-features opera://flags/#enable-experimental-web-platform-features edge://flags/#enable-experimental-web-platform-features chrome://flags/#enable-experimental-web-platform-features opera://flags/#enable-experimental-web-platform-features edge://flags/#enable-experimental-web-platform-features

References:参考:

https://dev.to/unjavascripter/the-amazing-powers-of-the-web-web-serial-api-3ilc https://dev.to/unjavascripter/the-amazing-powers-of-the-web-web-serial-api-3ilc

https://github.com/UnJavaScripter/web-serial-example https://github.com/UnJavaScripter/web-serial-example

Well, One way to do this is develop a chrome app.好吧,一种方法是开发一个 chrome 应用程序。 You can use chrome.serial API.您可以使用 chrome.serial API。

https://developer.chrome.com/apps/serial https://developer.chrome.com/apps/serial

Sample Code,示例代码,

In your manifest.json,在您的 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"]
    }
  }
}

In your 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);

Once you create the chrome app to communicate with the serial port the next thing is to allow your external web page to communicate with the chrome app using JavaScript.创建 chrome 应用程序以与串行端口通信后,接下来是允许您的外部网页使用 JavaScript 与 chrome 应用程序通信。

For this on your manifest.json file add,为此在您的 manifest.json 文件中添加,

"externally_connectable": {
"matches": ["*://*.example.com/*"]
}

This will allow external webpage on your example.com domain communicate with your chrome app.这将允许您 example.com 域上的外部网页与您的 chrome 应用程序通信。

In your webpage,在您的网页中,

    // 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);
   });

In your chrome app,在您的 Chrome 应用程序中,

chrome.runtime.onMessageExternal.addListener(
  function (request, sender, sendResponse) {
        sendResponse("Send serial port data to the web page");
  });

https://developer.chrome.com/apps/messaging https://developer.chrome.com/apps/messaging

I set up a website and a simple example for running a serial terminal in your browser.我建立了一个网站和一个在浏览器中运行串行终端的简单示例。 You should host it on a https server.您应该将其托管在 https 服务器上。

The serial terminal features are now available in chrome 88.串行终端功能现在在 chrome 88 中可用。

Live demo https://www.SerialTerminal.com Full source.现场演示https://www.SerialTerminal.com完整源代码。 https://github.com/mmiscool/serialTerminal.com/blob/main/index.html https://github.com/mmiscool/serialTerminal.com/blob/main/index.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Web应用程序通过串行端口进行通信 - Web application to communicate over serial port Web应用程序需要与串行端口通信 - Web app needs to communicate with serial port 使用Applet + Javascript从客户端(浏览器)读取串行端口 - Read serial port from client(Browser) using Applet + Javascript 如何使用javascript通过客户端串口进行通信? - how to communicate through serial port on client side using javascript? 我的Web应用程序如何与串行端口通信 - How can my web app communicate with serial port 浏览器中的Javascript下载文件。 网络API - Javascript download document in browser. Web API 访问 web worker 中的串口 - Access serial port in web worker 使用jssc和java applet与JS进行串行通信,但浏览器冻结 - using jssc and java applet to communicate to Serial with JS but browser freezes 从串口nodejs串口模块接收到的数据不正确 - Incorrect data received from serial port nodejs serial port module 使用 Node.js 访问特定网页时的 400 状态代码。 从我的浏览器点击同一个网页时出现 200 状态代码。 是什么赋予了? - 400 status code when using Node.js to hit a specific web page. And a 200 status code when hitting same web page from my browser. What gives?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM