Web Serial API'yi kullanmaya başlama

1. Giriş

Son Güncelleme: 19.09.2022

Oluşturacaklarınız

Bu codelab'de, BBC micro:bit panosuyla etkileşimde bulunmak için Web Serial API'yi kullanan bir web sayfası oluşturacaksınız. Bu kart, görüntüleri 5x5 LED matrisinde gösterir. Web Serial API ve tarayıcı üzerinden seri cihazlarla iletişim kurmak için okunabilir, yazılabilir ve dönüştürülebilir akışları nasıl kullanacağınız hakkında bilgi edineceksiniz.

67543f4caaaca5de.png

Neler öğreneceksiniz?

  • Web Seri bağlantı noktası nasıl açılır ve kapatılır?
  • Giriş akışından gelen verileri işlemek için okuma döngüsü kullanma
  • Verileri yazma akışı üzerinden gönderme

Gerekenler

Bu kod laboratuvarının uygun fiyatlı olması, birkaç giriş (düğme) ve çıkış (5x5 LED ekran) sunması ve ek giriş ve çıkışlar sağlayabilmesi nedeniyle micro:bit v1'i kullanmayı tercih ettik. micro:bit'in yapabildiği şeylerle ilgili ayrıntılar için Espruino sitesindeki BBC micro:bit sayfasına bakın.

2. Web Serial API hakkında

Web Serial API, web sitelerinin komut dosyaları kullanarak seri cihazlardan veri okumasına ve seri cihazlara veri yazmasına olanak tanır. API, web sitelerinin mikrodenetleyiciler ve 3D yazıcılar gibi seri cihazlarla iletişim kurmasına olanak tanıyarak web ile fiziksel dünya arasında köprü oluşturur.

Web teknolojisi kullanılarak oluşturulan kontrol yazılımlarına birçok örnek verilebilir. Örneğin:

Bazı durumlarda, bu web siteleri kullanıcı tarafından manuel olarak yüklenen bir yerel aracı uygulaması aracılığıyla cihazla iletişim kurar. Bazı durumlarda ise uygulama, Electron gibi bir çerçeve üzerinden paketlenmiş yerel bir uygulamada teslim edilir. Diğer durumlarda, kullanıcının, derlenmiş bir uygulamayı bir USB flash sürücüyle cihaza kopyalamak gibi ek bir işlem yapması gerekir.

Site ile kontrol ettiği cihaz arasında doğrudan iletişim sağlanarak kullanıcı deneyimi iyileştirilebilir.

3. Kurulum

Kodu alma

Bu codelab'de ihtiyacınız olan her şeyi bir Glitch projesine yerleştirdik.

  1. Yeni bir tarayıcı sekmesi açın ve https://web-serial-codelab-start.glitch.me/ adresine gidin.
  2. Başlangıç projesinin kendi sürümünüzü oluşturmak için Remiks Glitch bağlantısını tıklayın.
  3. Göster düğmesini tıklayın ve ardından kodunuzu çalışırken görmek için Yeni Pencerede'yi seçin.

4. Seri bağlantı açma

Web Serial API'nin desteklenip desteklenmediğini kontrol etme

Yapılacak ilk şey, Web Serial API'nin mevcut tarayıcıda desteklenip desteklenmediğini kontrol etmektir. Bunun için serial'ün navigator içinde olup olmadığını kontrol edin.

DOMContentLoaded etkinliğinde projenize aşağıdaki kodu ekleyin:

script.js - DOMContentLoaded

// CODELAB: Add feature detection here.
const notSupported = document.getElementById('notSupported');
notSupported.classList.toggle('hidden', 'serial' in navigator);

Bu işlem, Web Serisinin desteklenip desteklenmediğini kontrol eder. Reklam gösteriliyorsa bu kod, Web Serial'ın desteklenmediğini belirten banner'ı gizler.

Deneyin

  1. Sayfayı yükleyin.
  2. Sayfada, Web Serisinin desteklenmediğini belirten kırmızı bir banner görüntülenmediğinden emin olun.

Seri bağlantı noktasını açma

Ardından seri bağlantı noktasını açmamız gerekir. Diğer modern API'lerin çoğu gibi Web Serial API de asenkrondur. Bu, kullanıcı arayüzünün giriş beklerken engellenmesini önler. Ancak seri veriler web sayfası tarafından herhangi bir zamanda alınabileceğinden ve bu verileri dinlememize ihtiyaç duyulduğundan da önemlidir.

Bir bilgisayarda birden fazla seri cihaz olabileceğinden, tarayıcı bir bağlantı noktası isteğinde bulunmaya çalıştığında kullanıcıdan hangi cihaza bağlanacağını seçmesini ister.

Projenize aşağıdaki kodu ekleyin:

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 });

requestPort araması, kullanıcıdan hangi cihaza bağlanmak istediğini ister. port.open arandığında bağlantı noktası açılır. Ayrıca, seri cihazla iletişim kurmak istediğimiz hızı da sağlamamız gerekir. BBC micro:bit, USB'den seri çipe ve ana işlemciye 9.600 baud bağlantısı kullanır.

Bağlan düğmesini de bağlayalım ve kullanıcı düğmeyi tıkladığında connect() komutunu çağırmasını sağlayalım.

Projenize şu kodu ekleyin:

script.js - clickConnect()

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

Deneyin

Projemiz, başlangıç yapmak için artık minimum düzeyde. Bağlan düğmesi tıklandığında kullanıcıdan bağlanacağı seri cihazı seçmesi istenir, ardından micro:bit'e bağlanır.

  1. Sayfayı tekrar yükleyin.
  2. Bağlan düğmesini tıklayın.
  3. Seri Bağlantı Noktası seçici iletişim kutusunda, BBC micro:bit cihazını seçin ve Bağlan'ı tıklayın.
  4. Sekmede, seri cihaza bağlandığınızı belirten bir simge görürsünüz:

e695daf2277cd3a2.png

Seri bağlantı noktasından veri dinlemek için giriş akışı ayarlama

Bağlantı kurulduktan sonra, cihazdaki verileri okuyacak bir giriş akışı ve okuyucu ayarlamamız gerekir. Öncelikle port.readable işlevini çağırarak bağlantı noktasından okunabilir akışı alacağız. Cihazdaki metni geri alacağımızı bildiğimiz için bunu bir metin kod çözücüden faydalanacağız. Ardından bir okuyucu alır ve okuma döngüsünü başlatırız.

Projenize şu kodu ekleyin:

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();

Okuma döngüsü, döngü içinde çalışan ve ana iş parçacığını engellemeden içeriği bekleyen eşzamansız bir işlevdir. Yeni veriler geldiğinde okuyucu iki özellik döndürür: value ve bir done boole değeri. done true ise, bağlantı noktası kapatılmıştır veya başka veri gelmemektedir.

Projenize şu kodu ekleyin:

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;
  }
}

Deneyin

Projemiz artık cihaza bağlanabilir ve cihazdan alınan tüm veriler günlük öğesine eklenir.

  1. Sayfayı tekrar yükleyin.
  2. Bağlan düğmesini tıklayın.
  3. Seri Bağlantı Noktası seçici iletişim kutusunda BBC micro:bit cihazını seçin ve Bağlan'ı tıklayın.
  4. Espruino logosunu görürsünüz:

dd52b5c37fc4b393.png

Seri bağlantı noktasına veri göndermek için çıkış akışı oluşturma

Seri iletişim genellikle iki yönlüdür. Seri bağlantı noktasından veri almanın yanı sıra bağlantı noktasına veri de göndermek istiyoruz. Giriş akışında olduğu gibi yalnızca çıkış akışı üzerinden micro:bit'e metin göndereceğiz.

Öncelikle bir metin kodlayıcı akışı oluşturun ve akışı port.writeable'e aktarın.

script.js - connect()

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

Espruino donanım yazılımıyla seri bağlantıyla BBC micro:bit kartı, Node.js kabuğunda bulunana benzer şekilde JavaScript okuma-eval-yazdırma döngüsü (REPL) görevi görür. Ardından, akışa veri göndermek için bir yöntem sağlamamız gerekir. Aşağıdaki kod, çıkış akışından bir yazar alır ve ardından her satırı göndermek için write öğesini kullanır. Gönderilen her satırda, micro:bit'e gönderilen komutu değerlendirmesini bildiren bir yeni satır karakteri (\n) bulunur.

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();

Sistemi bilinen bir duruma getirmek ve gönderdiğimiz karakterleri geri yansıtmasını durdurmak için CTRL-C gönderip yankıyı kapatmamız gerekir.

script.js - connect()

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

Deneyin

Projemiz artık micro:bit'ten veri gönderip alabilir. Düzgün bir şekilde komut gönderebildiğimizi doğrulayalım:

  1. Sayfayı tekrar yükleyin.
  2. Bağlan düğmesini tıklayın.
  3. Seri Bağlantı Noktası seçici iletişim kutusunda, BBC micro:bit cihazını seçin ve Bağlan'ı tıklayın.
  4. Chrome Geliştirici Araçları'nda Konsol sekmesini açıp writeToStream('console.log("yes")'); yazın

Sayfada şuna benzer bir şey görürsünüz:

15e2df0064b5de28.png

5. LED matrisini kontrol etme

Matris ızgara dizesini oluşturma

micro:bit'teki LED matrisini kontrol etmek için show() işlevini çağırmamız gerekir. Bu yöntem, yerleşik 5x5 LED ekranda grafikler gösterir. Bu, ikilik sayı veya bir dize alır.

Onay kutularını tekrar tekrar kullanarak, hangisinin işaretli olduğunu, hangilerinin işaretlenmediğini gösteren bir 1 ve 0 dizisi oluşturacağız. Ardından, onay kutularımızın sırası matristeki LED'lerin sırasının tersi olduğu için diziyi tersine çevirmemiz gerekir. Ardından, diziyi bir dizeye dönüştürüp micro:bit'e gönderilecek komutu oluştururuz.

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('')})`);

Matrisi güncellemek için onay kutularını bağlayın

Ardından, onay kutularındaki değişiklikleri dinlememiz ve değişiklik olursa bu bilgileri micro:bit'e göndermemiz gerekir. Özellik algılama koduna (// CODELAB: Add feature detection here.) aşağıdaki satırı ekleyin:

script.js - DOMContentLoaded

initCheckboxes();

Ayrıca, micro:bit ilk bağlandığında ızgarayı sıfırlayarak mutlu bir yüz göstermesini sağlayalım. drawGrid() işlevi zaten sağlanmış. Bu işlev sendGrid() ile benzer şekilde çalışır; 1'ler ve 0'lardan oluşan bir dizi alır ve onay kutularını uygun şekilde işaretler.

script.js - clickConnect()

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

Deneyin

Artık sayfa, micro:bit ile bağlantı açtığında mutlu bir yüz gönderiyor. Onay kutularını tıkladığınızda LED matrisindeki ekran güncellenir.

  1. Sayfayı tekrar yükleyin.
  2. Bağlan düğmesini tıklayın.
  3. Seri Bağlantı Noktası seçici iletişim kutusunda, BBC micro:bit cihazını seçin ve Bağlan'ı tıklayın.
  4. micro:bit LED matrisinde bir gülümseme göreceksiniz.
  5. Onay kutularını değiştirerek LED matrisinde farklı bir desen çizin.

6. micro:bit düğmelerini kullanmaya başlayın

micro:bit düğmelerine izleme etkinliği ekleme

micro:bit'te, LED matrisinin her iki yanında birer düğme bulunur. Espruino, düğmeye basıldığında etkinlik/geri çağırma gönderen bir setWatch işlevi sağlar. Her iki düğmeyi de dinlemek istediğimiz için işlevimizi genel hale getirip etkinliğin ayrıntılarını yazdırmasını sağlayacağız.

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);

Ardından, seri bağlantı noktası cihaza her bağlandığında iki düğmeyi de (mikro:bit kartında BTN1 ve BTN2 olarak adlandırılır) bağlamamız gerekir.

script.js - clickConnect()

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

Deneyin

micro:bit bağlıyken mutlu bir yüz göstermenin yanı sıra, düğmelerden birine basıldığında sayfaya hangi düğmeye basıldığını belirten bir metin eklenir. Büyük olasılıkla her karakter kendi satırında olacaktır.

  1. Sayfayı tekrar yükleyin.
  2. Bağlan düğmesini tıklayın.
  3. Seri Bağlantı Noktası seçici iletişim kutusunda, BBC micro:bit cihazını seçin ve Bağlan'ı tıklayın.
  4. micro:bits LED matrisinde bir gülümseme göreceksiniz.
  5. micro:bit'teki düğmelere basın ve düğmenin ayrıntıları basılarak sayfaya yeni metin eklendiğini doğrulayın.

7. Gelen verileri ayrıştırmak için dönüştürme akışı kullanma

Temel akış işleme

micro:bit düğmelerinden birine basıldığında, micro:bit, verileri seri bağlantı noktasına bir akış üzerinden gönderir. Akışlar çok faydalıdır ancak aynı zamanda tüm verilere aynı anda erişemeyeceğiniz ve rastgele parçalanabilir. Bu nedenle de akışlar zorlayıcı olabilir.

Uygulama şu anda gelen akışı geldiği gibi (readLoop biçiminde) yazdırıyor. Çoğu durumda her karakter kendi satırındadır ancak bu pek yararlı değildir. İdeal olarak akış ayrı satırlara ayrıştırılmalı ve her mesaj kendi satırı olarak gösterilmelidir.

TransformStream ile akışları dönüştürme

Bunu yapmak için, gelen akışı ayrıştırmayı ve ayrıştırılan verileri döndürmeyi sağlayan bir dönüştürme akışı ( TransformStream) kullanabiliriz. Dönüşüm akışı, akış kaynağı (bu örnekte, micro:bit) ile akışı tüketen her şey (bu örnekte readLoop) arasında yer alabilir ve son olarak tüketilmeden önce rastgele bir dönüşüm uygulayabilir. Bunu bir montaj hattı gibi düşünebilirsiniz: Bir widget'ın ilerisinde olduğunda, satırdaki her adım widget'ı değiştirir. Böylece, son hedefine vardığında widget tam olarak çalışır hale gelir.

Daha fazla bilgi için MDN'nin Streams API kavramları başlıklı makaleyi inceleyin.

LineBreakTransformer ile akışı dönüştürün

Akışı alıp satır sonlarına (\r\n) göre parçalayacak bir LineBreakTransformer sınıfı oluşturalım. Sınıf için transform ve flush olmak üzere iki yöntem gerekli. transform yöntemi, akış her yeni veri aldığında çağrılır. Verileri sıraya alabilir veya daha sonra kullanmak üzere kaydedebilir. flush yöntemi, akış kapatıldığında çağrılır ve henüz işlenmemiş tüm verileri işler.

transform yöntemimizde, container değişkenine yeni veriler ekleyecek ve ardından container değişkeninde satır sonu olup olmadığını kontrol edeceğiz. Varsa dize bir diziye bölünür ve ardından satırlarda iterasyon yapılır. Ayrıştırılan satırlar controller.enqueue() çağrısı yapılarak gönderilir.

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));

Akış kapatıldığında, kapsayıcıda kalan tüm verileri enqueue kullanarak temizleyeceğiz.

script.js - LineBreakTransformer.flush()

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

Son olarak, gelen akışı yeni LineBreakTransformer üzerinden yönlendirmemiz gerekir. Orijinal giriş akışımız yalnızca TextDecoderStream üzerinden sağlanır. Bu nedenle, yeni LineBreakTransformer ile aktarması için ek bir pipeThrough eklememiz gerekiyor.

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()));

Deneyin

Artık micro:bit düğmelerinden birine bastığınızda yazdırılan veriler tek bir satırda döndürülecektir.

  1. Sayfayı tekrar yükleyin.
  2. Bağlan düğmesini tıklayın.
  3. Seri Bağlantı Noktası seçici iletişim kutusunda, BBC micro:bit cihazını seçin ve Bağlan'ı tıklayın.
  4. micro:bit LED matrisinde bir gülümseme göreceksiniz.
  5. micro:bit dosyasındaki düğmelere basın ve aşağıdakine benzer bir sonuç aldığınızı doğrulayın:

eead3553d29ee581.png

JSONTransformer ile akışı dönüştürün

Dizeyi readLoop içinde JSON biçimine ayrıştırmayı deneyebiliriz, ancak bunun yerine, verileri bir JSON nesnesine dönüştürecek çok basit bir JSON dönüştürücü oluşturalım. Veriler geçerli JSON değilse yalnızca gelen verileri döndürün.

script.js - JSONTransformer.transform

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

Ardından, LineBreakTransformer üzerinden geçtikten sonra JSONTransformer üzerinden akışı yönlendirin. JSON'un her zaman tek bir satırda gönderileceğini bildiğimiz için bu, JSONTransformer değerini basit tutmamızı sağlar.

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()));

Deneyin

Artık micro:bit düğmelerinden birine bastığınızda sayfada [object Object] ifadesini görürsünüz.

  1. Sayfayı tekrar yükleyin.
  2. Bağlan düğmesini tıklayın.
  3. Seri Bağlantı Noktası seçici iletişim kutusunda, BBC micro:bit cihazını seçin ve Bağlan'ı tıklayın.
  4. micro:bit LED matrisinde bir gülümseme gösterilir.
  5. micro:bit'teki düğmelere basın ve aşağıdakine benzer bir sonuç aldığınızı doğrulayın:

Düğmelere basıldığında yanıt verme

micro:bit düğmesi basmalarına yanıt vermek için readLoop uygulamasını, aldığı verilerin button özelliğine sahip bir object olup olmadığını kontrol edecek şekilde güncelleyin. Ardından, düğmeye basma işlemini gerçekleştirmek için buttonPushed öğesini çağırın.

script.js - readLoop()

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

Bir micro:bit düğmesine basıldığında LED matrisindeki ekran değişmelidir. Matrisi ayarlamak için aşağıdaki kodu kullanın:

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();
  }
}

Deneyin

Şimdi, micro:bit düğmelerinden birine bastığınızda LED matrisiniz mutlu veya üzgün bir yüze dönüşür.

  1. Sayfayı tekrar yükleyin.
  2. Bağlan düğmesini tıklayın.
  3. Seri Bağlantı Noktası seçici iletişim kutusunda, BBC micro:bit cihazını seçin ve Bağlan'ı tıklayın.
  4. micro:bits LED matrisinde bir gülümseme göreceksiniz.
  5. micro:bit'teki düğmelere basın ve LED matrisinin değiştiğini doğrulayın.

8. Seri bağlantı noktasını kapatma

Son adım, kullanıcı işi bittiğinde bağlantı noktasını kapatmak için bağlantı kesme işlevini bağlamaktır.

Kullanıcı Bağlan/Bağlantıyı Kes düğmesini tıkladığında bağlantı noktasını kapat

Kullanıcı Bağlan/Bağlantıyı kes düğmesini tıkladığında bağlantıyı kapatmamız gerekir. Bağlantı noktası zaten açıksa disconnect() yöntemini çağırın ve sayfanın artık seri cihaza bağlı olmadığını belirtmek için kullanıcı arayüzünü güncelleyin.

script.js - clickConnect()

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

Akışları ve bağlantı noktasını kapatma

disconnect işlevinde, giriş akışını, çıkış akışını ve bağlantı noktasını kapatmamız gerekir. Giriş akışını kapatmak için reader.cancel() komutunu çağırın. cancel çağrısı eşzamansız olduğundan, bu çağrının tamamlanmasını beklemek için await çağrısını kullanmamız gerekir:

script.js - disconnect()

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

Çıkış akışını kapatmak için bir writer alın, close() yöntemini çağırın ve outputDone nesnesinin kapatılmasını bekleyin:

script.js - disconnect()

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

Son olarak seri bağlantı noktasını kapatın ve kapanmasını bekleyin:

script.js - disconnect()

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

Deneyin

Artık seri bağlantı noktasını istediğiniz zaman açıp kapatabilirsiniz.

  1. Sayfayı tekrar yükleyin.
  2. Bağlan düğmesini tıklayın.
  3. Seri Bağlantı Noktası seçici iletişim kutusunda, BBC micro:bit cihazını seçin ve Bağlan'ı tıklayın.
  4. micro:bit LED matrisinde bir gülümseme gösterilir.
  5. Bağlantıyı kes düğmesine basıp LED matrisinin kapandığını ve konsolda herhangi bir hata olmadığını doğrulayın.

9. Tebrikler

Tebrikler! Web Serial API'yi kullanan ilk web uygulamanızı başarıyla derlediniz.

Web Seri API'si ve Chrome ekibinin üzerinde çalıştığı diğer heyecan verici yeni web özellikleri hakkında en son bilgiler için https://goo.gle/fugu-api-tracker adresini takip edin.