Web Serial Api podstawy
- Opublikowano • 2 min
Przykład komunikacji po porcie szeregowym
Przykład pochodzi z prezentacji JavaScript i IoT. Jak przy pomocy tego, co znasz zbudować coś namacalnego, którą przedstawiłem 15. października 2026 roku podczas wrocławskiego meet.js.
Web Serial API jest obecnie dobrze obsługiwane, w Chrome od wersji 89 a w Firefox od wersji 151 (Browser compatibility).
Narzędziownik
- JavaScript
- Obsługa Web Serial API
- Micropython
- Firmware dla Pico
- Raspberry Pi Pico 2 W
- Mikrokontroler
Firmware napisany w Micropython wypisuje na wyjściu pong jeżeli na wejściu dostaje ping.
Jako mikrokontrolera użyłem Raspberry Pi Pico 2 W.
import sys
print('Hello')
while True:
command = sys.stdin.readline().strip()
if command == 'ping':
print('pong')
Firmware wrzuciłem przy pomocy narzędzia mpremote (dokumentacja mpremote).
mpremote cp ./firmware.py :main.py + reset
Sprawdzamy listę podłączonych urządzeń i podłączamy się:
mpremote connect list
mpremote connect /dev/cu.usbmodem14401 # jeżeli port istnieje
Na wyjściu powinniśmy dostać:
Connected to MicroPython at /dev/cu.usbmodem14401
Use Ctrl-] or Ctrl-x to exit this shell
Hello
Wpiszmy ping, otrzymamy pong. Komunikacja po porcie szeregowym działa w dwie strony.
Connected to MicroPython at /dev/cu.usbmodem14401
Use Ctrl-] or Ctrl-x to exit this shell
Hello
ping
=> pong
A teraz spięcie z JavaScript
Specyfikacja mówi:
Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.
Użyłem vite do zbudowania projektu. Najpierw całość kodu:
let port, writer;
function send(command) {
// the firmware reads one command per line
return writer.write(new TextEncoder().encode(`${command}\n`));
}
// split incoming text into lines, data can arrive in arbitrary chunks
function splitLines() {
let buffer = "";
return new TransformStream({
transform(chunk, controller) {
buffer += chunk;
const lines = buffer.split("\n");
buffer = lines.pop();
lines.forEach((line) => controller.enqueue(line.trim()));
},
});
}
async function readLines() {
const lines = port.readable
.pipeThrough(new TextDecoderStream())
.pipeThrough(splitLines());
// Listen to data coming from the serial device.
for await (const line of lines) {
console.log(line);
}
}
async function connect() {
port = await navigator.serial.requestPort();
await port.open({ baudRate: 115200 });
writer = port.writable.getWriter();
readLines();
await send("ping");
}
function main() {
if ("serial" in navigator) {
document.querySelector("#web-serial-port-status").textContent =
"Web Serial Port is supported";
const connectButton = document.querySelector(".connect-button");
connectButton.hidden = false;
connectButton.addEventListener("click", connect);
}
}
main();
function main() {
if ("serial" in navigator) {
document.querySelector("#web-serial-port-status").textContent =
"Web Serial Port is supported";
const connectButton = document.querySelector(".connect-button");
connectButton.hidden = false;
connectButton.addEventListener("click", connect);
}
}
Jeżeli przeglądarka obsługuje Web Serial API połączenie z urządzeniem można wykonać dopiero po akcji użytkownika, np. kliknięciu w przycisk.
async function connect() {
port = await navigator.serial.requestPort();
await port.open({ baudRate: 115200 });
writer = port.writable.getWriter();
readLines();
await send("ping");
}
Po kliknięciu powinniśmy dostać listę urządzeń. Wartość baudRate: 115200 (bps) jest ściśle związana z mikrokontrolerem.
writer = port.writable.getWriter(); oraz port.readable kolejno pozwalają na zapisywanie i odczytywanie z urządzenia danych.
await send("ping") dodaje na koniec polecenia znak nowej lini:
function send(command) {
// the firmware reads one command per line
return writer.write(new TextEncoder().encode(`${command}\n`));
}
Zdjęcia dzięki uprzejmości Cezarego Dynaka, Aleksandry Pawlus oraz Adriana Romańskiego.
Cześć! Jestem otwarty na nowe wyzwania zawodowe.
Brzmi interesująco? Skontaktuj się ze mną poprzez poprzez LinkedIn

