19

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

Mawg says reinstate Monica
  • 34,839
  • 92
  • 281
  • 509

6 Answers6

24

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: enter image description here

Simon Mourier
  • 117,251
  • 17
  • 221
  • 269
  • 1
    That would work, but it would likely be quite difficult to implement. I'm not sure how challenging it is to write a Windows service, but installing it with the correct privileges will definitely require building a setup-program for it (there's tools for that, but you'd have to pick and learn one). Also, to actually access your service, you will need to do cross-domain XmlHttpRequests, which aren't that easy to do right if you want it to be cross-browser. Especially since you can't set "localhost" to the same document.domain as your server... But it's definitely a creative idea! ;) – Markus A. Mar 06 '13 at 03:17
  • It is an interesting take. I wonder - at that point - why are we using a browser at all? It seems like a I-have-a-hammer problem. If we're allowed to install a service on the front-end machine, it seems like the right approach is to go all-in: use a native Windows app and cut down the layers. You can host the HTML control if you want to maintain an HTML interface. For proper advice, it would help if we knew more details about the circumstances surrounding this product. – Euro Micelli Mar 06 '13 at 18:41
  • @EuroMicelli - well, the benefit of a web app is still you have to deploy a *minimum* set of components. This service may be only an .exe. My idea was to make it very generic, maybe up to the point it could be used by any web application - thinking about it, that's an interesting idea for a codeplex project... :-) – Simon Mourier Mar 06 '13 at 18:52
  • 1
    Reading all these comments, people seem to forget the legitimacy of using a web browser in order to access serial port hardware. In our case, I am searching for a very simplistic way to read data from a physical check scanner (MICR) in order to provide that data to an ecommerce store for order entry. Sure, I could create a windows forms app, but why would I when literally everything else is done within the web store interface? That's the beginning of fragmentation and confusion for employees doing the work. KISS = Keep It Simple, Stupid... – Ricky Jul 28 '14 at 17:03
11

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

Community
  • 1
  • 1
Markus A.
  • 11,761
  • 8
  • 44
  • 102
  • Where is the advantage of replacing an active-x component by a java-applet? Especially JNLP can be very hard to roll out in an managed it environment. Signing an applet is also not much fun either. – Chris Mar 11 '13 at 22:28
  • 3
    @Chris: AFAIK Java Applets are much more widely supported than ActiveX, which is mostly a Microsoft (Internet Explorer) invention (see original question). Also, writing and signing these applets is actually quite straight forward (I've done a few). But the MAJOR gain is when you try to call them from JavaScript. With a Java Applet, all you need to do is call it's public methods directly. Done. It's as straight forward, as you can possibly make it. Whereas some of the other solutions proposed here that involve an external HTTP service will require cross-site-scripting, which can be a HUGE pain. – Markus A. Mar 11 '13 at 23:16
  • 1
    agreed, the interaction between the java-applet and javascript is really straight forward and a lot more cross plattform then ActiveX. Just from my daily experience, the acceptance of java-applets is not on the rise. Due to widely discussed security problems, people tend do disable Java-Applets. I think it depends, if you desire an integrated plug-in like approach or a more pure web like approach. But +1 for the aspect of broader plattform support for java-applets in comparison to ActiveX – Chris Mar 11 '13 at 23:23
  • @Chris: Unfortunately you are right... Currently there is a bit of a push against Java because of the recent security problem (see "(for the most part)"-link above). But honestly, I don't really understand it. There are much worse problems in other software (like Windows) and fixes for Java are released at least as quickly via (semi-)automatic updates. So, I'm not sure the hate is justified. I personally find it extremely convenient, that I can code almost anything (websites, mobile apps, desktop apps, ...) in one language today. It'd be a huge bummer if this went away due to random politics. – Markus A. Mar 12 '13 at 00:02
  • 1
    Now that Java Applets are [no longer supported in browsers like Chrome](http://blog.chromium.org/2014/11/the-final-countdown-for-npapi.html), is there a new solution? – nerdwaller Apr 19 '15 at 12:14
  • @nerdwaller Since this seems to kill Java and SilverLight and more, I honestly don't know. Unfortunately I don't have time right now to dig into this deeper, but there might also be some alternative to the NPAPI that is being disabled. I doubt that Google will get rid of Chrome Extensions entirely. So, it is very possible that new (or even current?) versions of Java's JRE use a different API or will provide another kind of Chrome Extension to allow Applets to run in Chrome. Users might just have to install Java separately rather than relying on Chrome to do it for them... But, yes, this sucks! – Markus A. Apr 19 '15 at 22:07
7

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.

Chris
  • 2,111
  • 3
  • 22
  • 45
  • 1
    I am switching the accepted answer to this. Although Simon's answer was excellent, I don’t see the need for a web service. I had been thinking and independently arrived at this solution, so it must be good :-) Now all I need is to decide on hardware. Almost centrally a Raspberry Pi, but would a full blown 3 or a zer0 plus RS232 and Ethernet to WiFi be cheaper? See [related question](http://hardwarerecs.stackexchange.com/questions/6872/cmall-sheap-processor-with-serial-port-and-internet-access) – Mawg says reinstate Monica Feb 17 '17 at 09:15
  • 1
    You can use a raspberry pi. You can add a regular RS232 to the board, without the need for an additional USB-RS232 adapter. See this for reference: https://linhost.info/2016/02/test/ – Chris Feb 17 '17 at 23:55
  • Feel free to post an answer. Especially if you also add an internet solution. – Mawg says reinstate Monica Feb 17 '17 at 23:57
  • 1
    I would use a pi zero with the shown RS232 adapter. Easiest way to bridge the RS232 with REST would be to use python. I don't have a full solution on this. – Chris Feb 17 '17 at 23:59
  • 1
    @Mawg do you mean a solution that works over the internet? – Chris Feb 18 '17 at 11:38
  • Intranet, actually. `192.168.xxx.xxx` or `10.xxx.xxx.xxx` Just connecting my device to nearby laptop – Mawg says reinstate Monica Feb 18 '17 at 20:27
  • 1
    alright so it's a "secure" network. Not the public internet. Can you specify what will be connected to the Serial Port? – Chris Feb 18 '17 at 20:37
  • It doesn't matter. I just want to read/write at 9,600 baud, 8, N, 1 – Mawg says reinstate Monica Feb 18 '17 at 20:39
5

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.

Community
  • 1
  • 1
Euro Micelli
  • 31,089
  • 7
  • 46
  • 66
5

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.

AndyS
  • 600
  • 5
  • 14
  • 1
    This looks very interesting (+1). For anyone reading this in future, you can check browser support at https://caniuse.com/#search=webusb – Mawg says reinstate Monica Dec 11 '17 at 07:47
  • 1
    Interesting to see that Web USB now (claims to - not tested) work with Chrome for Android - see previous caniuse link. Not sure if this would need an OTG (on The Go) connection. – AndyS Feb 12 '18 at 20:43
2

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.

AndyS
  • 600
  • 5
  • 14