Signatur
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>) undwritable(WritableStream<Uint8Array>) sind die Datenkanäle. Sie sind erst nach dem Öffnen gesetzt, sonstnull.getInfo()liefertusbVendorIdundusbProductId(bei Bluetooth auchbluetoothServiceClassId).getSignals()undsetSignals()lesen bzw. setzen Steuerleitungen wie DTR, RTS, CTS, DSR, DCD und RI.forget()entzieht die Berechtigung für den Port.connectedzeigt an, ob das Gerät gerade physisch verbunden ist.- Die Ereignisse
connectunddisconnectmelden, 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
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)}`);
});
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;
};
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();
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);