Start · Sprachen · JavaScript · Referenz · SerialPort

SerialPort

Schnittstelle

Stellt einen seriellen Port des Host-Geräts dar (z. B. USB-Seriell-Adapter, Arduino) und bietet Streams zum Lesen und Schreiben von Bytes.

seit JavaScript Chrome/Edge 89+, Opera 75+ (experimentell, nicht i Kategorie: webapi

Signatur

interface SerialPort extends EventTarget

Beschreibung

Das Interface SerialPort gehört zur Web Serial API. Ein Objekt steht für einen einzelnen seriellen Port, etwa einen USB-CDC-Adapter, einen Mikrocontroller wie Arduino oder ESP32, ein GPS-Modul oder einen Barcode-Scanner. Instanzen erzeugst du nicht selbst. Du bekommst sie über navigator.serial.requestPort(), das nach einer Nutzeraktion einen Auswahldialog öffnet, oder über navigator.serial.getPorts(), das die schon freigegebenen Ports liefert.

Die wichtigsten Bestandteile:

  • open(options) öffnet den Port mit Baudrate und Rahmenformat. close() schließt ihn wieder.
  • readable (ReadableStream<Uint8Array>) und writable (WritableStream<Uint8Array>) sind die Datenkanäle. Sie sind erst nach dem Öffnen gesetzt, sonst null.
  • getInfo() liefert usbVendorId und usbProductId (bei Bluetooth auch bluetoothServiceClassId).
  • getSignals() und setSignals() lesen bzw. setzen Steuerleitungen wie DTR, RTS, CTS, DSR, DCD und RI.
  • forget() entzieht die Berechtigung für den Port. connected zeigt an, ob das Gerät gerade physisch verbunden ist.
  • Die Ereignisse connect und disconnect melden, wenn das Gerät angesteckt oder abgezogen wird.

Die Datenübertragung läuft vollständig über die Streams API. Du kannst also TextDecoderStream und TextEncoderStream oder eigene TransformStreams einbinden, etwa um Daten zeilenweise zu verarbeiten. Serielle Daten kommen dabei in beliebig großen Stücken an. Ein Lesevorgang liefert also nicht unbedingt eine vollständige Nachricht.

Parameter

Name Typ Default Beschreibung
$options.baudRate Pflicht number Übertragungsgeschwindigkeit in Bit/s für open(), z. B. 9600 oder 115200. Muss zum Gerät passen.
$options.dataBits 7 | 8 8 Anzahl der Datenbits pro Zeichen.
$options.stopBits 1 | 2 1 Anzahl der Stoppbits am Ende jedes Zeichens.
$options.parity "none" | "even" | "odd" "none" Paritätsmodus.
$options.bufferSize number 255 Größe der Lese- und Schreibpuffer in Byte (kleiner als 16 MiB).
$options.flowControl "none" | "hardware" "none" Flusskontrolle. "hardware" nutzt RTS/CTS.

Rückgabewert

Typ
SerialPort
Beschreibung
Instanzen gibt es nur über navigator.serial.requestPort() (Promise<SerialPort>) oder navigator.serial.getPorts() (Promise<SerialPort[]>). open(), close(), setSignals() und forget() liefern Promise<void>.

Beispiele

Port auswählen, öffnen und Geräteinfo auslesen

const connectBtn = document.querySelector('#connect');

connectBtn.addEventListener('click', async () => {
  if (!('serial' in navigator)) {
    console.warn('Web Serial API wird nicht unterstützt');
    return;
  }
  // Nur Arduino-Geräte anzeigen (USB-Hersteller-ID 0x2341)
  const port = await navigator.serial.requestPort({
    filters: [{ usbVendorId: 0x2341 }]
  });
  await port.open({ baudRate: 115200 });

  const { usbVendorId, usbProductId } = port.getInfo();
  console.log(`Verbunden: VID=0x${usbVendorId.toString(16)}, PID=0x${usbProductId.toString(16)}`);
});
Verbunden: VID=0x2341, PID=0x43

Text lesen mit TextDecoderStream

const readLoop = async (port) => {
  const decoder = new TextDecoderStream();
  const pipeDone = port.readable.pipeTo(decoder.writable);
  const reader = decoder.readable.getReader();
  let buffer = '';

  try {
    while (true) {
      const { value, done } = await reader.read();
      if (done) break;
      buffer += value;
      // Nur vollständige Zeilen ausgeben
      const lines = buffer.split('\n');
      buffer = lines.pop();
      lines.forEach((line) => console.log('Gerät:', line.trim()));
    }
  } finally {
    reader.releaseLock();
    await pipeDone.catch(() => {});
  }
  return reader;
};
Gerät: Temperatur=22.5 Gerät: Temperatur=22.6

Befehl senden und Port sauber schließen

const sendCommand = async (port, command) => {
  const writer = port.writable.getWriter();
  try {
    await writer.write(new TextEncoder().encode(command + '\r\n'));
  } finally {
    writer.releaseLock(); // Sperre freigeben, sonst schlägt close() fehl
  }
};

const [port] = await navigator.serial.getPorts();
await port.open({ baudRate: 9600 });
await sendCommand(port, 'LED ON');

// Steuerleitung DTR setzen (z. B. für einen Reset)
await port.setSignals({ dataTerminalReady: false });
console.log(await port.getSignals());

await port.close();
{ clearToSend: true, dataCarrierDetect: false, dataSetReady: true, ringIndicator: false }

Auf Anstecken und Abziehen reagieren

const onConnect = (event) => console.log('Angeschlossen:', event.target.getInfo());
const onDisconnect = (event) => console.log('Getrennt:', event.target.getInfo());

// Global für alle freigegebenen Ports
navigator.serial.addEventListener('connect', onConnect);
navigator.serial.addEventListener('disconnect', onDisconnect);

// Oder direkt am Port über die on-Eigenschaft
const [port] = await navigator.serial.getPorts();
if (port) {
  port.ondisconnect = () => console.log('Dieser Port wurde abgezogen');
}

// Später wieder entfernen
navigator.serial.removeEventListener('connect', onConnect);
Getrennt: { usbVendorId: 9025, usbProductId: 67 }