How can a web page read from the user's serial port - in the year 2017?

I have to re-implement an existing system from scratch.

At one point, when the user navigates to a certain web page the server must read data from the user's serial port.

Currently, the web page has an ActiveX control; when the page is loaded the ActiveX control calls into a COM DLL on the user's PC which reads data from the serial port.

The system is 10 years old. Is there any "better" way that I could implement this?

For instance, technology has move on in the last ten years. And this solution seems only to work in MS IE, which now has a market share of about 26% (it had, in 2013, when I last updated this question. As of Feb 2107, MS IE has 3-4% and Edge has 1-2%. As Edge is also a MS product, it might support Active X - I have not tried. Otoh, since it is new from the ground up, there is a good chance that it does not).

Did HTML 5 offer any new possibilities? What about products like Cordova?

Are there any other possibilities?

Could I add a Raspberry Pi to do the reading over serial port & and have the browser app communicate with that over a RESTful service?


[Update] @ EuroMicelli said "I'm going to assume that you have a very good reason to run your app from a web browser, instead of a native app". I don't know as I wasn't around when the original project was planned (and the company which designed it is now defunct).

Perhaps they didn't want the end user interfacing directly with the database? Perhaps "browser based" was a new buzzword back then? I, personally, have no problem with a desktop app (as I find them easier to implement), but maybe we should consider remaining browser based? (besides, I can handle the desktop app myself; it's only browser based reading from the COM port that leads me to offer a bonus ;-)

Answers


Just to name another (more like "web-of-things") option: external hardware.

Depending on the use-case you COULD use an external low cost device like an arduino microcontroller or raspberry-pi embedded pc.

It's not very difficult to build a simple serial to web-service bridge upon these kind of devices. You could use some projects like this e.g. : https://code.google.com/p/serwebproxy/

In such a scenario all the low level stuff is handled by the external hardware and is offered to you by a web-service like interface (via get/post).

Further advantage is that the pc, where you application runs on, doesn't need a serial port (which becomes quite rare on some systems).

From your browser application you could query the web-service on the embedded device with a simple ajax call. The browser wouldn't need any plugin at all, the solution works cross plattform and is generic and independent from the development of browser-technologies in the near future.


One thing for sure, you will never be able to communicate with the local machine hardware without installing some special binaries (and run it with appropriate privileges) on the local machine. However, that doesn't mean you necessary need to use an ActiveX component and stay stuck with Internet Explorer. Of course, you could also develop a component for every browser in the market.

I suggest another approach:

  • Write a Windows Service (I assume your machine runs Windows), configure it with necessary privileges. You will have to install something on the machine anyway. The service can be implemented in any language.
  • Add HTTP(S) server capabilities to it. You can use a lot of technologies here from WCF to WebAPI.
  • Invent your own communication protocol over HTTP. You could use JSON, Ajax, WebSockets, SignalR, etc.
  • Write a Javascript file that will be compatible with most browsers on the market - so you only have to write that once - that will become your Serial COM API. You can support all browsers with Javascript and Ajax capabilities (XmlHttpRequest), with only one code base.

Here is how it would look like:


To minimize external library or plugin requirements on the client machines, I would write a Java Applet.

Summary (including links to most of the documentation you will need to make it happen):

  1. Make sure your clients have Java installed (most do already and if not, the browser can install it) (this is the only install you may need to require from some of your clients for this approach)
  2. Pick a Java serial port library that doesn't require any external installs, like PureJavaComm
  3. Write a very simple Java applet that provides public methods to do the serial port read
  4. Sign your applet so that it is granted the required system access privileges
  5. Include the applet in your webpage and simply call the public methods directly from JavaScript

More details:

According to StatOwl, about two-thirds of all machines have the required Java frameworks already installed, so you might not even need to ask your clients to provide any additional infrastructure. And if you do, at least you are asking for a (for the most part) well-maintained piece of software that people know and won't be too skeptical about. And, most browsers should have the ability to prompt your users to install the Java framework automatically if it's missing.

There are several different libraries you can use in Java to access the serial port. PureJavaComm seems to be one of the few, though, that don't require external code to run. Specifically, on Windows, their WinAPI Java class gives you direct access to COM ports including all their settings just using calls to the already installed Windows libraries. Since PureJavaComm is a Java-only library, you can package it with your applet in one .jar file, which the browser downloads automatically, so there is nothing to install.

You can then write a minimal Java Applet (probably only around 50-100 lines total) that defines public methods to do the serial port access you need, which you can then easily call from JavaScript directly: Invoking Applet Methods From JavaScript Code

The only thing you need to make sure is that you sign your applet and that you wrap your serial port code in doPrivileged(...) calls so that it will be granted the required system access from within the JVM Sandbox. For this, you can either get a hold of a purchased SSL certificate (which you may already have if your service uses https) or generate your own. If you generate your own, the users will be prompted, whether they want to trust your applet, but they can choose "always trust" and so it's just a one-time checkbox- and ok-click. But beyond that, this should be a completely transparent solution that will minimize impact on your user-experience.

Alternative 1:

Another option would be, to simply ditch the web-interface altogether and instead provide a Java program that users can easily run (with or without installing it) directly from your website using JNLP (Java Web Start).

Alternative 2 (Likely Windows only):

I guess you could also use Microsoft Silverlight, which also seems fairly widely deployed:

Serial Communication with Silverlight 5 (COM port)

Some might consider it more "modern" than Java Applets, but it's probably less cross-platform.

It also seems a bit more involved to call your Silverlight code from JavaScript, but it is possible:

Making Silverlight Scriptable by JavaScript


Probably not.

I'm going to assume that you have a very good reason to run your app from a web browser, instead of a native app. I can think of a couple of scenarios where I can see that being a justifiable business decision.

Even today with all the modern advances, web browsers are still fancy interactive document viewers, not universal runtime environments. Even the most cutting-edge features like websockets were introduced to enable sophisticated client-server communications, and not because of some universal interest to one day being able to do everything from the browser.

There might be some specialized environment where that is natively possible (does Chrome OS?), but it won't be a general solution. There is no existing or proposed standard I'm aware of to open serial ports via a browser tag or scripting. That means you will need some kind of fairly low-level plug-in technology like ActiveX. ActiveX is a really good solution if you are Ok with IE only support, particularly if it's already written and it works.

Most people looking for serial port access from a browser are probably doing data acquisition from some proprietary hardware they specify (build/sell?) and control, such as lab equipment, bar code scanners, scientific instruments, etc. I think at that point it is also perfectly acceptable to specify the required browser as well. Specialized applications commonly do that.

If you still want to look at wider browser support, try looking at the proposed solution for this question: Communicating with Serial Port using Adobe Flash. I don't have experience with this product, but if it works it ought to enable most browsers to do what you want to do with a single codebase, and that's as good as you can hope.

Whatever you end-up doing, it will most certainly involve some form of third-party plug-in.


You could use Web USB - but browser compatibility is (currently) very low - Chrome 61 seems to be about it.

The main benefit of this approach, is that the usb device is plugged into the browser machine. Apparently this works for Chrome for Android 64 as well (not tested).

The API is at https://wicg.github.io/webusb/.

For a tutorial see https://developers.google.com/web/updates/2016/03/access-usb-devices-on-the-web.


Using the serialport package through Node JS as a server is an option. This works on Windows, and apparently on Linux and OSX as well. See https://github.com/node-serialport/node-serialport.

This is a solution I have used to read micro bit comms through USB to a browser. I did have to rebuild the driver for windows (10) with:

  • npm install --global --production windows-build-tools
  • npm install serialport --build-from-source

I've pasted some of my code below for reference:

const serialport = require('serialport')

// list serial ports:
const find_microbit = (error, success) => {
  serialport.list((err, ports) => {
    if (err) {
      error(err)
    } else {
      let comName = null
      ports.forEach((port) => {
        if ((port.vendorId == '0D28') && (port.productId == '0204')) {
          comName = port.comName
        }
      })
      if (comName != null) {
        success(comName)
      } else {
        error('Could not find micro:bit.')
      }
    }
  })
}

exports.get_serial = (error, success) => {
  find_microbit(error, (comName) => {
    let serial = new serialport(comName, {baudRate: 115200, parser: serialport.parsers.readline('\n')}, (err) => {
      if (err) {
        error(err)
      } else {
        success(serial)
      }
    })
  })
}
/* e.g.
get_serial((err)=>{console.log("Error:" + err)},
    (serial)=>{
        serial.on('data', (data) => {
            let ubit = JSON.parse(data)
            if (ubit.button == 'a') {
                console.log('Button A Pressed')
            }
            if (ubit.button == 'b') {
                console.log('Button B Pressed')
            }
            if (ubit.ir) {
                console.log('Visitor detected')
            }
        })
    })
    */

This approach works - for me - but it can be time consuming to get it working. It's not, to my mind, an obvious, or simple solution. It requires a fair amount of technical know how - and is, I feel, much more complex and 'tricky' than it should be.

In particular - rebuilding the library isn't something I would expect to do when using Node JS. One of the possible effects is that you would need to rebuild the serial port binaries for a different platform.


Need Your Help

Tracking scroll position and notifying other components about it

angular typescript events scroll

Is there an easy way to track the browser scroll position and notify more than a single component about it?

/usr/bin/codesign failed with exit code 1

iphone ios xcode deployment code-signing

I am attempting to deploy my first development iPhone app, and am running into some problems. I have successfully went though the online Provisioning Assistant, but now I am stuck. No matter what...