Reading data from the usb port in Javascript

Node.js and websockets came to the rescue when I needed to read data from a USB-powered barcode scanner

node.js,serial,web sockets

11/20/2015

I have a web-based application which needed to be able to read barcodes from museum visitors via a USB barcode reader. The web application was already using node.js to transmit other data via web sockets between the back and front end, so I figured I'd see if there was a way to utilize node to read the serial port data from USB and transmit that to the web application as well.

Luckily, people are awesome, and someone had already created a node serial port library. I created a git repo where you can see some simple examples of how to read serial data with node and send it to your web application. The readme file is fairly thorough, but I thought I'd explain the process from a high-level perspective here.

Due to security concerns, you can't just go having any web application reading information about devices plugged in to a user's computer. If so, someone could hack it and potentially do things like take control of your webcam. But node.js can read serial data, and then it can broadcast that data to any web application which happens to be listening to the correct address / port.

In order to do this, you need to download nodejs, install it, and install all the modules necessary for reading serial data and broadcasting it via websockets. In the case of our git repo, we can broadcast via two different methods, ws - which is a simpler / lighter / faster method of communication, or socket i/o, which is more robust, but probably a bit overblown for a simple barcode reader. Then you run the node application responsible for receiving and sending data, and then load the web page responsible for listening for websocket messages from node. Node detects serial data, it broadcasts the message through websockets, and the web page receives the barcode data and you do what you want with it.

Just a note about serial data - it is transmitted in bytes, and often the message transmitted isn't easily human readable. In the case of my barcode reader, it's just a number. But other devices, such as an arduino, might send along more complex messages. If your device is sending a lot of data, it will often include a delimiter, which is just a bit of code that signals the end of a message. Node's serial port library can be configured to detect that signal in order to broadcast a message only when it sees the end of the message. Often, the delimiter is a newline character ("\n"). For the barcode reader, there is no delimiter, so we are simply sending the raw barcode data. But, because it is raw data, and the data comes in one byte at a time, the serial library stores that data in an Array Buffer. Otherwise, if your barcode was a number such as 1234, you would send each number "1","2",3","4". So when the number is complete, the serial port library sends along that array buffer. However, front end javascript code, can't read the array buffer easily, so in nodejs, we need to convert that buffer into a string, by simply type casting it with javascript's string function (string(ArrayBuffer));

Another important thing to note is that the serialport library depends on you knowing the name of your serial port. This name can be unique depending on the device you are using. For macs, it is often something like "/dev/cu.usbmodem1421". But the port name is not always the same, even on your own computer it can changed, depending on what else you have plugged in to other ports on your computer, because the port name is dynamically assigned. For example, if you plug in an arduino to a USB port before you plug the barcode reader into another, the arduino might take the name "/dev/cu.usbmodem1421" and the barcode reader would take the next default name. For this reason, I've included the listports.js node file, which allows you to loop through all the ports on your computer and find the proper name.

Lastly, just keep in mind that the port number for websockets is arbitrary, and has nothing to do with the port name of your serial port. You can set it to basically anything you want, within a reasonable range. But you need to make sure that it is not in use by any other application. For the socketio example, we are using port 3000. For the ws example, we're using port 8081. There should be no reason to change these numbers unless you have a conflict, but if you do, be sure to avoid common port numbers like 21 (FTP), 80 (HTTP), or 8888 (MAMP, if you're running a local server).

Download the git repo here.