# serialport-web

[![CI](https://github.com/monteslu/serialport-web/actions/workflows/ci.yml/badge.svg)](https://github.com/monteslu/serialport-web/actions/workflows/ci.yml)
[![npm version](https://img.shields.io/npm/v/serialport-web.svg)](https://www.npmjs.com/package/serialport-web)
[![npm downloads](https://img.shields.io/npm/dm/serialport-web.svg)](https://www.npmjs.com/package/serialport-web)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Web Serial API for the browser. Use serial ports with Firmata and Johnny-Five.

Successor to [browser-serialport](https://github.com/monteslu/browser-serialport), updated for the modern Web Serial API.

Part of the `-web` family of browser implementations:
- [http-web](https://github.com/monteslu/http-web) - HTTP for browser
- [net-web](https://github.com/monteslu/net-web) - TCP sockets for browser
- **serialport-web** - Serial ports for browser

## Requirements

- Browser with Web Serial API support (Chrome, Edge, Opera)
- HTTPS (required by Web Serial API)
- User gesture for initial port selection

## Installation

```bash
npm install serialport-web
```

## Usage

### Basic Usage with SerialPort Class

```javascript
import { SerialPort, requestPort } from 'serialport-web';

// First, request user to select a port (requires user gesture like button click)
const button = document.getElementById('connect');
button.addEventListener('click', async () => {
  // Request port selection
  const { port } = await requestPort();

  // Open the port
  const serial = new SerialPort({
    _port: port,  // Pass the selected port
    baudRate: 57600,
  });

  serial.on('open', () => {
    console.log('Port opened!');
  });

  serial.on('data', (data) => {
    console.log('Received:', data);
  });

  // Write data
  serial.write('Hello Arduino!');
});
```


### Using with Firmata

```javascript
import { SerialPort, requestPort } from 'serialport-web';
import { Firmata } from 'firmata';

const button = document.getElementById('connect');
button.addEventListener('click', async () => {
  const { port } = await requestPort();

  const transport = new SerialPort({
    _port: port,
    baudRate: 57600,
  });

  const board = new Firmata(transport);

  board.on('ready', () => {
    console.log('Firmata ready!');
    // Blink LED on pin 13
    let state = true;
    setInterval(() => {
      board.digitalWrite(13, state ? 1 : 0);
      state = !state;
    }, 500);
  });
});
```

### Using with Johnny-Five

```javascript
import { SerialPort, requestPort } from 'serialport-web';
import { Board, Led } from 'johnny-five';
import { Firmata } from 'firmata';

const button = document.getElementById('connect');
button.addEventListener('click', async () => {
  const { port } = await requestPort();

  const transport = new SerialPort({
    _port: port,
    baudRate: 57600,
  });

  const io = new Firmata(transport);

  io.on('ready', () => {
    const board = new Board({ io, repl: false });

    board.on('ready', () => {
      const led = new Led(13);
      led.blink(500);
    });
  });
});
```

## API

### `requestPort(filters?)`

Request user to select a serial port. Must be called from a user gesture (click, etc.).

```javascript
import { requestPort } from 'serialport-web';

// No filters - show all ports
const { port, path, vendorId, productId } = await requestPort();

// With filters - only show specific devices
const { port } = await requestPort({ usbVendorId: 0x2341 }); // Arduino
```

Returns:
- `port` - The Web Serial API port object (pass to SerialPort as `_port`)
- `path` - Generated path string for this port
- `vendorId` - USB vendor ID (hex string) if available
- `productId` - USB product ID (hex string) if available

### `isSupported()`

Check if Web Serial API is available.

```javascript
import { isSupported } from 'serialport-web';

if (isSupported()) {
  // Show connect button
} else {
  // Show "not supported" message
}
```

### `SerialPort`

EventEmitter-style serial port class compatible with Firmata and Johnny-Five.

```javascript
import { SerialPort } from 'serialport-web';

const port = new SerialPort({
  _port: webSerialPort,
  baudRate: 9600,
  dataBits: 8,
  stopBits: 1,
  parity: 'none',
});

port.on('open', () => { });
port.on('data', (data) => { });
port.on('error', (err) => { });
port.on('close', () => { });

port.write(new Uint8Array([0x01, 0x02, 0x03]));
port.write('string data');
port.close();
```

### Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `_port` | SerialPort | required | Web Serial API port from `requestPort()` |
| `baudRate` | number | required | Baud rate (9600, 57600, 115200, etc.) |
| `dataBits` | number | 8 | Data bits (7 or 8) |
| `stopBits` | number | 1 | Stop bits (1 or 2) |
| `parity` | string | 'none' | Parity ('none', 'even', 'odd') |
| `flowControl` | string | 'none' | Flow control ('none' or 'hardware') |
| `bufferSize` | number | 255 | Read buffer size |

## Browser Support

Web Serial API is supported in:
- Chrome 89+
- Edge 89+
- Opera 75+

**Not supported in:** Firefox, Safari

## Notes

- The Web Serial API requires HTTPS (or localhost)
- Initial port selection requires a user gesture (button click, etc.)
- Once a port is selected, it can be reconnected without user gesture
- Use `navigator.serial.getPorts()` or `SerialPort.list()` to get previously-granted ports

## License

MIT

## Author

Luis Montes ([@monteslu](https://github.com/monteslu))
