The amazing powers of the web: Web Serial API
Tags: webdev, arduino, javascript, serial
Published: 2020-04-09 19:07:20

# The Web Serial API

The Web Serial API allows us to interact with serial devices by sending and receiving data from within a web browser.

Using this API we can select and connect to a serial device, and then send and receive messages in just a couple of lines of JavaScript code.

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. At this moment you need to enable your browser's **Experimental Web Platform Features**, just copy and paste the right URL:

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

## Why?

Why not? This API brings one more capability to the more widespread platform, the web. Having access to physical devices will make it easier for people with web development knowledge to start diving into the waters of the IoT movement by interfacing with it through the browser, a familiar platform for them.

So dust off that Arduino you may have laying around, connect it to your computer and let's begin connecting the web and the physical world.


## How?

### Connection

After validating if _serial_ is supported by the browser, we use the `requestPort` method to prompt the user with a Browser provided UI displaying a list of available serial devices.

![list of serial devices](https://user-images.githubusercontent.com/7959823/78915668-901c3800-7a8c-11ea-91eb-9b0d5fb6f259.png)

We then `open` a port to connect with that device. Here the `baudRate` needs to match the baud rate used by the device. The expected baud rate values are:

```
115200, 57600, 38400, 19200, 9600, 4800, 2400, 1800, 1200, 600, 300, 200, 150, 134, 110, 75, 50
```

Using the `readable` [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) and `writable` [WriteableStream](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) properties that we get from the port we create a reader and a writer.

```js
if ('serial' in navigator) {
  try {
    const port = await navigator.serial.requestPort();
    await port.open({ baudRate: 9600 });
    this.reader = port.readable.getReader();
    this.writer = port.writable.getWriter();
  }
  catch (err) {
    console.error('There was an error opening the serial port:', err);
  }
}
else {
  console.error('The Web serial API doesn\'t seem to be enabled in your browser.');
}
```

Here we're storing both the reader and the writer objects globally for later use.


### Reading and Writing

The data that is transferred between the browser and the device is encoded, so we need to create an **encoder** to use when _sending_ a message and a **decoder** to be able to properly _read_ a message.

```js
constructor() {
  this.encoder = new TextEncoder();
  this.decoder = new TextDecoder();
}
```


#### Writing

Writing data, or sending a message, is really easy. First we take the message we wish to send and _encode_ it, then using the `write` method of the global writer object we previously created.

```js
async write(data) {
  const dataArrayBuffer = this.encoder.encode(data);
  return await this.writer.write(dataArrayBuffer);
}
```

The `write` method returns a promise that we can use to validate the completion of the write process.


#### Reading

The reading process is actually similar to the write one, using the reader's `read` method we get the data that's coming from the device and pass it to the decorder's `decode` method.

```js
async read() {
  try {
    const readerData = await this.reader.read();
    return this.decoder.decode(readerData.value);
  }
  catch (err) {
    const errorMessage = `error reading data: ${err}`;
    console.error(errorMessage);
    return errorMessage;
  }
}
```

Here we can catch any reading error and do something with it.

That's it! that's the basic setup of a Web Serial API handler.

## Examples

![serial-basic](https://user-images.githubusercontent.com/7959823/78914167-534f4180-7a8a-11ea-9bcc-049aa3244a3a.gif)

The basic example uses a regular Arduino without any additional hardware. When sending a `1` as a message the Arduino's onboard LED will light up, when sending `0` it'll turn off.

- Demo: [https://unjavascripter-web-serial-example.glitch.me/](https://unjavascripter-web-serial-example.glitch.me/)
- Code: [https://github.com/UnJavaScripter/web-serial-example](https://github.com/UnJavaScripter/web-serial-example)

---

![serial and LED Matrix](https://user-images.githubusercontent.com/7959823/78929050-f95a7600-7aa1-11ea-993e-50b0905a7c8d.gif)


The "advanced" example keeps the same Web Serial API handler code, it just adds some extra bits to the client side code. It also expects the user to have a **MAX7219** controlled **8x8 LED matrix**, a really affordable and easy to get LED matrix.

- Demo: [https://unjavascripter-web-serial-led-matrix.glitch.me/](https://unjavascripter-web-serial-led-matrix.glitch.me/)
- Code: [https://github.com/UnJavaScripter/web-serial-led-matrix](https://github.com/UnJavaScripter/web-serial-led-matrix)


## Origin Trial
> Update: Web Serial API is promoted to _stable_ from Chrome 89. This means that an Origin Trial token is not required anymore.

Origin trials enable us to ship experimental features without having our users enable flags in their browsers. Check out more here: [https://github.com/GoogleChrome/OriginTrials](https://github.com/GoogleChrome/OriginTrials) and here [https://developers.chrome.com/origintrials/](https://developers.chrome.com/origintrials/)

## Browser support

- Chrome
  - Experimental: 80+
  - Stable: 89+
- Edge (Chromium based)
- Opera (you need to enable it's flag in opera://flags/#enable-experimental-web-platform-features)

## Further reading

- WICG's Serial API Draft: [https://wicg.github.io/serial/](https://wicg.github.io/serial/)
- WICG's Serial API Explainer: [https://github.com/WICG/serial/blob/gh-pages/EXPLAINER.md](https://github.com/WICG/serial/blob/gh-pages/EXPLAINER.md)
- Google's Weg Serial Codelab: [https://codelabs.developers.google.com/codelabs/web-serial/#0](https://codelabs.developers.google.com/codelabs/web-serial/#0)


## Next steps

Chromium + Web Serial API + Raspberry Pi == Awesomeness 🔥