Memulai Web Serial API

Terakhir Diperbarui: 08-11-2019

Yang akan Anda build

Dalam codelab ini, Anda akan membuat halaman web yang menggunakan Web Serial API untuk berinteraksi dengan papan BBC micro:bit untuk menampilkan gambar pada matriks LED 5x5. Anda akan mempelajari Web Serial API dan cara menggunakan streaming yang dapat dibaca, ditulis, dan ditransformasi untuk berkomunikasi dengan perangkat serial melalui browser.

Yang akan Anda pelajari

  • Cara membuka dan menutup port Serial Web
  • Cara menggunakan loop baca untuk menangani data dari aliran input
  • Cara mengirim data melalui stream tulis

Yang Anda butuhkan

Kami memilih untuk menggunakan micro:bit untuk codelab ini karena cukup terjangkau, menawarkan beberapa input (tombol) dan output (layar LED 5x5), dan dapat memberikan input dan output tambahan. Lihat halaman micro:bit BBC di situs Espruino untuk mengetahui detail tentang kemampuan mikro:bit.

Web Serial API menyediakan cara bagi situs untuk membaca dan menulis ke perangkat serial dengan skrip. API tersebut menjembatani web dan dunia nyata dengan mengizinkan situs web berkomunikasi dengan perangkat serial, seperti pengontrol mikro dan printer 3D.

Ada banyak contoh software kontrol yang dibuat menggunakan teknologi web. Misalnya:

Dalam beberapa kasus, situs tersebut berkomunikasi dengan perangkat melalui aplikasi agen asli yang diinstal secara manual oleh pengguna. Dalam kasus lain, aplikasi dikirimkan dalam aplikasi native paket melalui framework seperti Electron. Dalam kasus lain, pengguna harus melakukan langkah tambahan, seperti menyalin aplikasi yang dikompilasi ke perangkat dengan flash drive USB.

Pengalaman pengguna dapat ditingkatkan dengan menyediakan komunikasi langsung antara situs dan perangkat yang dikontrol situs.

Mengaktifkan Web Serial API

Web Serial API saat ini sedang dalam pengembangan dan hanya tersedia di belakang flag. Anda harus mengaktifkan flag #enable-experimental-web-platform-features di chrome://flags.

Mendapatkan kode

Kami telah menyiapkan semua yang Anda perlukan untuk codelab ini ke dalam project Glitch.

  1. Buka tab browser baru dan buka https://web-serial-codelab-start.glitch.me/.
  2. Klik link Remix Glitch untuk membuat versi awal project awal Anda.
  3. Klik tombol Show, lalu pilih In a New Window untuk melihat cara kerja kode Anda.

Periksa apakah Web Serial API didukung

Hal pertama yang harus dilakukan adalah memeriksa apakah Web Serial API didukung di browser saat ini. Untuk melakukannya, periksa apakah serial ada di navigator.

Di peristiwa DOMContentLoaded, tambahkan kode berikut ke project Anda:

script.js - DOMContentLoaded

// CODELAB: Add feature detection here.
if ('serial' in navigator) {
  const notSupported = document.getElementById('notSupported');
  notSupported.classList.add('hidden');
}

Tindakan ini untuk memeriksa apakah Serial Web didukung atau tidak. Jika didukung, kode ini akan menyembunyikan banner yang menyatakan bahwa Serial Web tidak didukung.

Coba

  1. Muat halaman.
  2. Pastikan bahwa halaman tidak menampilkan banner merah yang menyatakan bahwa Serial Web tidak didukung.

Buka port serial

Selanjutnya, kita perlu membuka port serial. Seperti kebanyakan API modern lainnya, Web Serial API bersifat asinkron. Ini mencegah UI memblokir saat menunggu input, tetapi ini juga penting karena data serial dapat diterima oleh halaman web kapan saja, dan kita memerlukan cara untuk memprosesnya.

Karena komputer dapat memiliki beberapa perangkat serial, saat browser mencoba meminta transfer, tindakan ini akan meminta pengguna untuk memilih perangkat mana yang akan dihubungkan.

Tambahkan kode berikut ke project Anda:

script.js - connect()

// CODELAB: Add code to request & open port here.
// - Request a port and open a connection.
port = await navigator.serial.requestPort();
// - Wait for the port to open.
await port.open({ baudrate: 9600 });

Panggilan requestPort akan meminta pengguna untuk tersambung ke perangkat mana. Memanggil port.open akan membuka port. Kita juga perlu memberikan kecepatan saat kita ingin berkomunikasi dengan perangkat serial. Micro:bit BBC menggunakan koneksi 9600 baud antara chip USB-ke-serial dan prosesor utama.

Mari juga hubungkan tombol hubungkan dan minta connect() memanggil saat pengguna mengkliknya.

Tambahkan kode berikut ke project Anda:

script.js - clickConnect()

// CODELAB: Add connect code here.
await connect();

Coba

Project kami kini memiliki batas minimum untuk memulai. Mengklik tombol Connect akan meminta pengguna memilih perangkat serial untuk dihubungkan, lalu terhubung ke micro:bit.

  1. Muat ulang halaman.
  2. Klik tombol Hubungkan.
  3. Pada dialog pemilih Serial Port, pilih perangkat micro:bit BBC dan klik Connect.
  4. Di tab, Anda akan melihat ikon yang menunjukkan bahwa Anda telah terhubung ke perangkat serial:

Menyiapkan aliran input untuk memproses data dari port serial

Setelah koneksi terbentuk, kita perlu menyiapkan aliran data input dan pembaca untuk membaca data dari perangkat. Pertama, kita akan mendapatkan aliran yang dapat dibaca dari port dengan memanggil port.readable. Karena kami tahu bahwa kami akan mendapatkan teks kembali dari perangkat, kami akan memasukkannya melalui dekoder teks. Selanjutnya, kita akan mendapatkan pembaca dan memulai loop baca.

Tambahkan kode berikut ke project Anda:

script.js - connect()

// CODELAB: Add code to read the stream here.
let decoder = new TextDecoderStream();
inputDone = port.readable.pipeTo(decoder.writable);
inputStream = decoder.readable;

reader = inputStream.getReader();
readLoop();

Loop baca adalah fungsi asinkron yang berjalan di loop dan menunggu konten tanpa memblokir thread utama. Saat data baru tiba, pembaca akan menampilkan dua properti: boolean value dan done. Jika done benar, port telah ditutup atau tidak ada data lain yang masuk.

Tambahkan kode berikut ke project Anda:

script.js - readLoop()

// CODELAB: Add read loop here.
while (true) {
  const { value, done } = await reader.read();
  if (value) {
    log.textContent += value + '\n';
  }
  if (done) {
    console.log('[readLoop] DONE', done);
    reader.releaseLock();
    break;
  }
}

Coba

Project kita sekarang dapat terhubung ke perangkat dan akan menambahkan data yang diterima dari perangkat ke elemen log.

  1. Muat ulang halaman.
  2. Klik tombol Hubungkan.
  3. Pada dialog pemilih Serial Port, pilih perangkat micro:bit BBC dan klik Connect.
  4. Anda akan melihat logo Espruino:

Menyiapkan aliran output untuk mengirim data ke port serial

Komunikasi serial biasanya dua arah. Selain menerima data dari port serial, kami juga ingin mengirim data ke port tersebut. Seperti dengan aliran input, kita hanya akan mengirim teks melalui stream output ke micro:bit.

Pertama, buat streaming encoder teks dan transfer streaming tersebut ke port.writeable.

script.js - connect()

// CODELAB: Add code setup the output stream here.
const encoder = new TextEncoderStream();
outputDone = encoder.readable.pipeTo(port.writable);
outputStream = encoder.writable;

Saat terhubung melalui serial dengan firmware Espruino, board micro:bit BBC berfungsi sebagai read-eval-print loop (REPL) JavaScript, mirip dengan yang Anda dapatkan di shell Node.js. Selanjutnya, kita perlu menyediakan metode untuk mengirim data ke aliran data. Kode di bawah mendapatkan penulis dari aliran output, lalu menggunakan write untuk mengirim setiap baris. Setiap baris yang dikirim menyertakan karakter baris baru (\n), untuk memberi tahu mikro:bit agar mengevaluasi perintah yang dikirimkan.

script.js - writeToStream()

// CODELAB: Write to output stream
const writer = outputStream.getWriter();
lines.forEach((line) => {
  console.log('[SEND]', line);
  writer.write(line + '\n');
});
writer.releaseLock();

Untuk mengubah status sistem yang diketahui dan menghentikannya menggaungkan kembali karakter yang kita kirim, kita perlu mengirim CTRL-C dan menonaktifkan gema.

script.js - connect()

// CODELAB: Send CTRL-C and turn off echo on REPL
writeToStream('\x03', 'echo(false);');

Coba

Project kita kini dapat mengirim dan menerima data dari micro:bit. Mari kita verifikasi bahwa kita dapat mengirim perintah dengan benar:

  1. Muat ulang halaman.
  2. Klik tombol Hubungkan.
  3. Pada dialog pemilih Serial Port, pilih perangkat micro:bit BBC dan klik Connect.
  4. Buka tab Console di Chrome DevTools, lalu ketik
    writeToStream('console.log("yes")');

Anda akan melihat sesuatu seperti ini dicetak di halaman:

Membuat string petak matriks

Untuk mengontrol matriks LED pada mikro:bit, kita perlu memanggil show(). Metode ini menampilkan grafik pada layar LED 5x5 bawaan. Tindakan ini memerlukan angka biner atau string.

Kami akan melakukan iterasi pada kotak centang dan menghasilkan array 1 dan 0 yang menunjukkan kotak yang dicentang dan yang tidak. Kemudian, kita harus membalikkan array, karena urutan kotak centang kita berkebalikan dengan urutan LED dalam matriks. Selanjutnya, kita mengonversi array ke string dan membuat perintah untuk dikirim ke micro:bit.

script.js - sendGrid()

// CODELAB: Generate the grid
const arr = [];
ledCBs.forEach((cb) => {
  arr.push(cb.checked === true ? 1 : 0);
});
writeToStream(`show(0b${arr.reverse().join('')})`);

Mengaitkan kotak centang untuk memperbarui matriks

Selanjutnya, kita harus memantau perubahan pada kotak centang dan, jika berubah, mengirimkan informasi tersebut ke micro:bit. Dalam kode deteksi fitur (// CODELAB: Add feature detection here.), tambahkan baris berikut:

script.js - DOMContentLoaded

initCheckboxes();

Mari kita reset grid saat micro:bit pertama kali terhubung, agar bisa menampilkan wajah senang. Fungsi drawGrid() sudah disediakan. Fungsi ini bekerja mirip dengan sendGrid(); fungsi ini memerlukan array 1 dan 0, serta mencentang kotak yang sesuai.

script.js - clickConnect()

// CODELAB: Reset the grid on connect here.
drawGrid(GRID_HAPPY);
sendGrid();

Coba

Sekarang, saat koneksi terbuka ke mikro:bit, halaman akan mengirimkan wajah senang. Mengklik kotak centang akan memperbarui tampilan di matriks LED.

  1. Muat ulang halaman.
  2. Klik tombol Hubungkan.
  3. Pada dialog pemilih Serial Port, pilih perangkat micro:bit BBC dan klik Connect.
  4. Anda akan melihat senyuman yang ditampilkan pada matriks LED mikro:bit.
  5. Gambar pola lain pada matriks LED dengan mengubah kotak centang.

Menambahkan peristiwa tonton pada tombol mikro:bit

Ada dua tombol di micro:bit, satu di kedua sisi matriks LED. Espruino menyediakan fungsi setWatch yang mengirimkan peristiwa/callback saat tombol ditekan. Karena kita ingin mendengarkan kedua tombol, kita akan membuat fungsi kita generik dan membuatnya mencetak detail peristiwa.

script.js - watchButton()

// CODELAB: Hook up the micro:bit buttons to print a string.
const cmd = `
  setWatch(function(e) {
    print('{"button": "${btnId}", "pressed": ' + e.state + '}');
  }, ${btnId}, {repeat:true, debounce:20, edge:"both"});
`;
writeToStream(cmd);

Selanjutnya, kita perlu menghubungkan kedua tombol (bernama BTN1 dan BTN2 pada papan mikro:bit) setiap kali port serial terhubung ke perangkat.

script.js - clickConnect()

// CODELAB: Initialize micro:bit buttons.
watchButton('BTN1');
watchButton('BTN2');

Coba

Selain menampilkan wajah senang saat terhubung, menekan salah satu tombol di micro:bit akan menambahkan teks ke halaman yang menunjukkan tombol mana yang ditekan. Kemungkinan besar, setiap karakter akan berada di barisnya sendiri.

  1. Muat ulang halaman.
  2. Klik tombol Hubungkan.
  3. Pada dialog pemilih Serial Port, pilih perangkat micro:bit BBC dan klik Connect.
  4. Anda akan melihat senyuman yang ditampilkan pada matriks LED mikro:bit.
  5. Tekan tombol di micro:bit dan pastikan bahwa teks baru telah ditambahkan ke halaman dengan detail tombol ditekan.

Penanganan streaming dasar

Saat salah satu tombol mikro:bit didorong, micro:bit mengirimkan data ke port serial melalui aliran. Streaming sangat berguna, tetapi juga dapat menjadi tantangan karena Anda tidak perlu mendapatkan semua data sekaligus, dan mungkin akan dipotong secara acak.

Aplikasi saat ini mencetak aliran masuk saat tiba (dalam readLoop). Di sebagian besar kasus, setiap karakter berada di barisnya masing-masing, tetapi hal tersebut tidak terlalu membantu. Idealnya, aliran harus diurai menjadi baris terpisah, dan setiap pesan ditampilkan sebagai barisnya sendiri.

Mentransformasi aliran dengan TransformStream

Untuk melakukannya, kita dapat menggunakan aliran transformasi (TransformStream), yang memungkinkan untuk mengurai aliran masuk dan menampilkan data yang diuraikan. Stream transformasi dapat berada di antara sumber aliran data (dalam hal ini, mikro:bit), dan apa pun yang menggunakan aliran data (dalam hal ini readLoop), dan dapat menerapkan transformasi arbitrer sebelum akhirnya digunakan. Bayangkan hal ini seperti garis perakitan: Saat widget menurun, setiap langkah di garis memodifikasi widget tersebut, sehingga pada saat mencapai tujuan akhirnya, widget tersebut menjadi widget yang berfungsi penuh.

Untuk informasi selengkapnya, lihat Konsep Streams API API MDN'.

Mentransformasi aliran dengan LineBreakTransformer

Mari kita buat class LineBreakTransformer, yang akan mengambil aliran data dan mengelompokkannya berdasarkan jeda baris (\r\n). Class ini memerlukan dua metode, transform dan flush. Metode transform dipanggil setiap kali data baru diterima oleh aliran data. Dapat mengantrekan data atau menyimpannya untuk nanti. Metode flush dipanggil saat streaming ditutup, dan metode ini menangani data apa pun yang belum diproses.

Dalam metode transform, kita akan menambahkan data baru ke container, lalu memeriksa apakah ada baris baru di container. Jika ada, bagi menjadi array, lalu lakukan iterasi pada baris, dengan memanggil controller.enqueue() untuk mengirimkan baris yang terurai.

script.js - LineBreakTransformer.transform()

// CODELAB: Handle incoming chunk
this.container += chunk;
const lines = this.container.split('\r\n');
this.container = lines.pop();
lines.forEach(line => controller.enqueue(line));

Ketika streaming ditutup, kami hanya akan membersihkan semua data yang tersisa di penampung menggunakan enqueue.

script.js - LineBreakTransformer.flush()

// CODELAB: Flush the stream.
controller.enqueue(this.container);

Terakhir, kita harus menyalurkan aliran masuk melalui LineBreakTransformer baru. Aliran input asli hanya disalurkan melalui TextDecoderStream, sehingga kita perlu menambahkan pipeThrough tambahan untuk menyalurkannya melalui LineBreakTransformer baru.

script.js - connect()

// CODELAB: Add code to read the stream here.
let decoder = new TextDecoderStream();
inputDone = port.readable.pipeTo(decoder.writable);
inputStream = decoder.readable
  .pipeThrough(new TransformStream(new LineBreakTransformer()));

Coba

Sekarang, saat Anda menekan salah satu tombol mikro:bit, data yang dicetak akan ditampilkan dalam satu baris.

  1. Muat ulang halaman.
  2. Klik tombol Hubungkan.
  3. Pada dialog pemilih Serial Port, pilih perangkat micro:bit BBC dan klik Connect.
  4. Anda akan melihat senyuman yang ditampilkan pada matriks LED mikro:bit.
  5. Tekan tombol di micro:bit dan verifikasi bahwa Anda melihat sesuatu seperti berikut:

Mentransformasi aliran dengan JSONTransformer

Kita dapat mencoba menguraikan string menjadi JSON di readLoop, tetapi mari kita buat transformator JSON sederhana yang akan mengubah data menjadi objek JSON. Jika data bukan JSON yang valid, cukup tampilkan yang masuk.

script.js - JSONTransformer.transform

// CODELAB: Attempt to parse JSON content
try {
  controller.enqueue(JSON.parse(chunk));
} catch (e) {
  controller.enqueue(chunk);
}

Berikutnya, transfer streaming melalui JSONTransformer, setelah melewati LineBreakTransformer. Hal ini memungkinkan kita membuat JSONTransformer tetap sederhana, karena kita tahu bahwa JSON hanya akan dikirim dalam satu baris.

script.js - connect

// CODELAB: Add code to read the stream here.
let decoder = new TextDecoderStream();
inputDone = port.readable.pipeTo(decoder.writable);
inputStream = decoder.readable
  .pipeThrough(new TransformStream(new LineBreakTransformer()))
  .pipeThrough(new TransformStream(new JSONTransformer()));

Coba

Sekarang, saat Anda menekan salah satu tombol mikro:bit, Anda akan melihat [object Object] dicetak di halaman.

  1. Muat ulang halaman.
  2. Klik tombol Hubungkan.
  3. Pada dialog pemilih Serial Port, pilih perangkat micro:bit BBC dan klik Connect.
  4. Anda akan melihat senyuman yang ditampilkan pada matriks LED mikro:bit.
  5. Tekan tombol di micro:bit, lalu verifikasi bahwa Anda melihat sesuatu seperti berikut:

Merespons penekanan tombol

Untuk merespons penekanan tombol mikro:bit, update readLoop untuk memeriksa apakah data yang diterima adalah object dengan properti button. Kemudian, panggil buttonPushed untuk menangani penekanan tombol.

script.js - readLoop()

const { value, done } = await reader.read();
if (value && value.button) {
  buttonPushed(value);
} else {
  log.textContent += value + '\n';
}

Saat tombol mikro:bit didorong, tampilan pada matriks LED akan berubah. Gunakan kode berikut untuk menetapkan matriks:

script.js - buttonPushed()

// CODELAB: micro:bit button press handler
if (butEvt.button === 'BTN1') {
  divLeftBut.classList.toggle('pressed', butEvt.pressed);
  if (butEvt.pressed) {
    drawGrid(GRID_HAPPY);
    sendGrid();
  }
  return;
}
if (butEvt.button === 'BTN2') {
  divRightBut.classList.toggle('pressed', butEvt.pressed);
  if (butEvt.pressed) {
    drawGrid(GRID_SAD);
    sendGrid();
  }
}

Coba

Sekarang, ketika Anda menekan salah satu tombol mikro:bit, matriks LED akan berubah menjadi wajah senang atau wajah sedih.

  1. Muat ulang halaman.
  2. Klik tombol Hubungkan.
  3. Pada dialog pemilih Serial Port, pilih perangkat micro:bit BBC dan klik Connect.
  4. Anda akan melihat senyuman yang ditampilkan pada matriks LED mikro:bit.
  5. Tekan tombol di micro:bit, dan pastikan matriks LED berubah.

Langkah terakhir adalah menghubungkan fungsi pemutusan koneksi untuk menutup port saat pengguna selesai.

Menutup port saat pengguna mengklik tombol Hubungkan/Putuskan koneksi

Saat pengguna mengklik tombol Hubungkan/Putuskan sambungan, kita harus menutup koneksi. Jika port sudah terbuka, panggil disconnect() dan update UI untuk menunjukkan bahwa halaman tidak lagi terhubung ke perangkat serial.

script.js - clickConnect()

// CODELAB: Add disconnect code here.
if (port) {
  await disconnect();
  toggleUIConnected(false);
  return;
}

Menutup streaming dan port

Pada fungsi disconnect, kita harus menutup aliran data input, menutup aliran data output, dan menutup port. Untuk menutup aliran data input, panggil reader.cancel(). Panggilan ke cancel bersifat asinkron, sehingga kita harus menggunakan await untuk menunggunya selesai:

script.js - disconnect()

// CODELAB: Close the input stream (reader).
if (reader) {
  await reader.cancel();
  await inputDone;
  reader = null;
  inputDone = null;
}

Untuk menutup aliran data output, dapatkan writer, panggil close(), dan tunggu objek outputDone ditutup:

script.js - disconnect()

// CODELAB: Close the output stream.
if (outputStream) {
  await outputStream.getWriter().close();
  await outputDone;
  outputStream = null;
  outputDone = null;
}

Terakhir, tutup port serial dan tunggu hingga port tersebut ditutup:

script.js - disconnect()

// CODELAB: Close the port.
await port.close();
port = null;

Coba

Sekarang, Anda dapat membuka dan menutup port serial sesuai keinginan.

  1. Muat ulang halaman.
  2. Klik tombol Hubungkan.
  3. Pada dialog pemilih Serial Port, pilih perangkat micro:bit BBC dan klik Connect.
  4. Anda akan melihat senyuman yang ditampilkan pada matriks LED mikro:bit
  5. Tekan tombol Putuskan sambungan dan pastikan matriks LED mati dan tidak ada kesalahan di konsol.

Selamat! Anda telah berhasil membuat aplikasi web pertama Anda yang menggunakan Web Serial API.

Nantikan https://goo.gle/fugu-api-tracker untuk yang terbaru di Web Serial API dan semua kemampuan web baru yang menarik lainnya yang sedang dikerjakan tim Chrome.