Web Serial API'yi kullanmaya başlama

1. Giriş

Son güncelleme: 2020-07-21

Ne oluşturacaksınız?

Bu codelab'de, 5x5 LED matrisinde resim göstermek için BBC micro:bit kartıyla etkileşim kurmak üzere Web Serial API'yi kullanan bir web sayfası oluşturacaksınız. 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.

81167ab7c01d353d.png

Neler öğreneceksiniz?

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

Gerekenler

Bu codelab'de micro:bit'i seçmemizin nedeni, uygun fiyatlı olması, birkaç giriş (düğme) ve çıkış (5x5 LED ekran) sunması ve ek giriş ve çıkış sağlayabilmesidir. micro:bit'in neler yapabileceği hakkında ayrıntılı bilgi için Espruino sitesindeki BBC micro:bit sayfasına bakın.

2. Web Serial API hakkında

Web Serial API, web sitelerinin komut dosyalarıyla seri cihazlardan okuma ve seri cihazlara yazma işlemleri yapmasına olanak tanır. API, web sitelerinin mikro denetleyiciler ve 3D yazıcılar gibi seri cihazlarla iletişim kurmasına izin vererek web ile fiziksel dünya arasında köprü kurar.

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

Bazı durumlarda bu web siteleri, kullanıcı tarafından manuel olarak yüklenen yerel bir aracı uygulaması aracılığıyla cihazla iletişim kurar. Diğer durumlarda ise uygulama, Electron gibi bir çerçeve aracılığıyla paketlenmiş bir yerel uygulama olarak sunulur. Diğer durumlarda ise kullanıcının ek bir adım gerçekleştirmesi gerekir. Örneğin, derlenmiş bir uygulamayı USB flash sürücü ile cihaza kopyalaması gerekir.

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

3. Hazırlanma

Kodu alma

Bu codelab için 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 Remix Glitch bağlantısını tıklayın.
  3. Göster düğmesini tıklayın ve kodunuzun nasıl çalıştığını görmek için Yeni Pencerede'yi seçin.

4. Seri bağlantı açma

Web Serial API'nin desteklenip desteklenmediğini kontrol etme

İlk olarak, Web Serial API'nin mevcut tarayıcıda desteklenip desteklenmediğini kontrol edin. Bunu yapmak için serial öğesinin 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, Web Serial'ın desteklenip desteklenmediğini kontrol eder. Bu kod, Web Serial'ın desteklenmediğini belirten banner'ı gizler.

Deneyin

  1. Sayfayı yükleyin.
  2. Sayfada, Web Serial'ın desteklenmediğini belirten kırmızı bir banner gösterilmediğini doğrulayın.

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

Ardından, seri bağlantı noktasını açmamız gerekir. Diğer modern API'lerin çoğu gibi Web Serial API de eşzamansızdır. Bu, giriş beklenirken kullanıcı arayüzünün engellenmesini önler. Ayrıca, seri veriler web sayfası tarafından herhangi bir zamanda alınabileceğinden ve bunları dinlemenin bir yolunu bulmamız gerektiğinden de önemlidir.

Bir bilgisayarda birden fazla seri cihaz bulunabileceğinden tarayıcı bir bağlantı noktası istemeye ç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 görüşmesi, kullanıcıya hangi cihaza bağlanmak istediğini sorar. port.open numarası 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-seri çip ile ana işlemci arasında 9600 baud bağlantı kullanır.

Ayrıca, bağlantı düğmesini bağlayalım ve kullanıcı tıkladığında connect() işlevini çağırmasını sağlayalım.

Projenize aşağıdaki kodu ekleyin:

script.js - clickConnect()

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

Deneyin

Projemiz artık başlatmak için gereken minimum özelliklere sahip. Bağlan düğmesini tıkladığınızda kullanıcıdan bağlanılacak seri cihazı seçmesi istenir ve ardından micro:bit'e bağlanılı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örmeniz gerekir:

d9d0d3966960aeab.png

Seri bağlantı noktasından gelen verileri dinlemek için bir giriş akışı ayarlama

Bağlantı kurulduktan sonra, cihazdaki verileri okumak için bir giriş akışı ve okuyucu oluşturmamız gerekir. İlk olarak, port.readable işlevini çağırarak bağlantı noktasından okunabilir akışı alacağız. Cihazdan metin yanıtı alacağımızı bildiğimiz için bu yanıtı bir metin kod çözücüden geçiririz. Ardından, bir okuyucu alıp okuma döngüsünü başlatacağız.

Projenize aşağıdaki 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çerik bekleyen eşzamansız bir işlevdir. Yeni veriler geldiğinde okuyucu iki özellik döndürür: value ve done Boole değeri. done doğruysa bağlantı noktası kapatılmıştır veya artık veri gelmemektedir.

Projenize aşağıdaki 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 verileri günlük öğesine ekleyebilir.

  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örmelisiniz:

93494fd58ea835eb.png

Verileri seri bağlantı noktasına göndermek için bir çıkış akışı ayarlama

Seri iletişim genellikle çift 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, çıkış akışında da micro:bit'e yalnızca metin gönderilir.

Öncelikle bir metin kodlayıcı yayını oluşturun ve yayını port.writeable'ya yönlendirin.

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ı üzerinden bağlandığında BBC micro:bit kartı, Node.js kabuğunda elde ettiğinize benzer şekilde JavaScript read-eval-print loop (REPL) olarak işlev görür. Ardından, akışa veri gönderme yöntemi 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 kullanır. Gönderilen her satır, micro:bit'e gönderilen komutu değerlendirmesini söylemek için yeni satır karakteri (\n) içerir.

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 tekrar göndermesini durdurmak için CTRL-C göndermemiz ve 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. 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çın ve writeToStream('console.log("yes")'); yazın.

Sayfada aşağıdakine benzer bir şey yazılı olmalıdır:

a13187e7e6260f7f.png

5. LED matrisi kontrol etme

Matris tablosu dizesini oluşturma

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

Onay kutularını yineleyip hangisinin işaretli olduğunu ve hangisinin işaretli olmadığını gösteren 1'ler ve 0'lardan oluşan bir dizi oluşturacağız. Ardından, onay kutularımızın sırası matristeki LED'lerin sırasının tersi olduğundan diziyi tersine çevirmemiz gerekir. Ardından, diziyi 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ğlama

Ardından, onay kutularındaki değişiklikleri dinlememiz ve değişirlerse 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 kez bağlandığında ızgarayı sıfırlayarak yüz göstermesini sağlayalım. drawGrid() işlevi zaten sağlanıyor. Bu işlev, sendGrid() işlevine benzer şekilde çalışır. 1 ve 0 dizisi 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 yüz gönderir. 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österilir.
  5. Onay kutularını değiştirerek LED matrisinde farklı bir desen çizin.

6. micro:bit düğmelerini bağlama

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

micro:bit'te iki düğme bulunur. Bu düğmelerden biri LED matrisinin bir tarafında, diğeri ise diğer tarafında yer alır. Espruino, düğmeye basıldığında bir etkinlik/geri çağırma gönderen bir setWatch işlevi sağlar. İki düğmeyi de dinlemek istediğimiz için işlevimizi genel hale getirecek ve 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 her iki düğmeyi (micro: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

Bağlandığında yüz göstermenin yanı sıra micro:bit üzerindeki 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 yer alı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:bit'in LED matrisinde bir gülümseme görürsünüz.
  5. micro:bit'teki düğmelere basın ve basılan düğmeyle ilgili ayrıntıları içeren yeni metnin sayfaya 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 biri itildiğinde micro:bit, bir akış aracılığıyla seri bağlantı noktasına veri gönderir. Akışlar çok faydalı olsa da tüm verileri aynı anda alamayacağınız ve verilerin rastgele parçalara ayrılacağı için zorluklar yaşayabilirsiniz.

Uygulama şu anda gelen akışı geldiği gibi (readLoop içinde) yazdırıyor. Çoğu durumda her karakter ayrı bir satırda yer alıyor ancak bu pek kullanışlı değil. İdeal olarak, yayın ayrı satırlar halinde ayrıştırılmalı ve her mesaj kendi satırında gösterilmelidir.

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

Bunu yapmak için gelen akışı ayrıştırmayı ve ayrıştırılmış verileri döndürmeyi mümkün kılan bir dönüştürme akışı ( TransformStream) kullanabiliriz. Dönüştürme akışı, akış kaynağı (bu örnekte micro:bit) ile akışı tüketen öğe (bu örnekte readLoop) arasında yer alabilir ve nihai olarak tüketilmeden önce rastgele bir dönüştürme uygulayabilir. Bunu bir montaj hattı gibi düşünebilirsiniz: Bir widget hat boyunca ilerlerken hattaki her adımda widget değiştirilir. Böylece, son hedefine ulaştığında tam işlevsel bir widget olur.

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

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

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

transform yöntemimizde, transform öğesine yeni veriler ekleyip container içinde satır sonu olup olmadığını kontrol edeceğiz.container Varsa bunu bir diziye bölün ve ardından ayrıştırılan satırları göndermek için controller.enqueue() işlevini çağırarak satırları yineleyin.

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ıdaki kalan veriler enqueue kullanılarak temizlenir.

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 yönlendirildiği için yeni LineBreakTransformer üzerinden yönlendirmek üzere 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ülmelidir.

  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 şey gördüğünüzü doğrulayın:

6c2193880c748412.png

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

Dizeyi readLoop içinde JSON'a ayrıştırmayı deneyebiliriz ancak bunun yerine verileri JSON nesnesine dönüştürecek çok basit bir JSON dönüştürücü oluşturalım. Veriler geçerli JSON değilse gelen verileri olduğu gibi 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, akışı LineBreakTransformer'dan geçirdikten sonra JSONTransformer üzerinden yönlendirin. JSON'un yalnızca tek bir satırda gönderileceğini bildiğimiz için JSONTransformer'ımızı basit tutabiliriz.

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] simgesini görmeniz gerekir.

  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 üzerindeki düğmelere basın ve aşağıdakine benzer bir şey gördüğünüzü doğrulayın:

Düğmeye basma işlemlerine yanıt verme

micro:bit düğmesine basma işlemlerine yanıt vermek için readLoop öğesini, aldığı verilerin button özelliği olan bir object olup olmadığını kontrol edecek şekilde güncelleyin. Ardından, düğmeye basma işlemini gerçekleştirmek için buttonPushed işlevini ç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

Artık micro:bit düğmelerinden birine bastığınızda LED matrisi mutlu veya üzgün yüz olarak değişmelidir.

  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'in LED matrisinde bir gülümseme görürsünüz.
  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şini bitirdiğinde bağlantıyı kesme işlevini kullanarak bağlantı noktasını kapatmaktı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() işlevini ç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ı kapatın

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() işlevini çağırın. cancel işlevi eşzamansız olduğundan tamamlanmasını beklemek için await işlevini 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 writer alın, close() ç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örürsünüz.
  5. Bağlantıyı kaldır düğmesine basın ve LED matrisinin kapandığını, konsolda hata olmadığını doğrulayın.

9. Tebrikler

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

Web Serial API ve Chrome ekibinin üzerinde çalıştığı diğer tüm heyecan verici yeni web özellikleri hakkında en son bilgileri https://goo.gle/fugu-api-tracker adresinden takip edebilirsiniz.