Web Serial API'yi kullanmaya başlama

1. Giriş

Son Güncelleme Tarihi: 21.07.2020

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 hakkında bilgi edinecek ve seri cihazlarla tarayıcı üzerinden iletişim kurmak için okunabilir, yazılabilir ve dönüştürme akışlarının nasıl kullanılacağını öğreneceksiniz.

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
  • Yazma akışı üzerinden veri gönderme

Gerekenler

Bu codelab'in uygun maliyetli olması, birkaç giriş (düğme) ve çıkışı (5x5 LED ekran) sunması, ek giriş ve çıkışlara imkan vermesi nedeniyle bu codelab için micro:bit 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ıyla bir seri cihazda okuma ve yazma işlemleri yapması için bir yol sağlar. 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ü kurar.

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ıyı 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. Bunun için serial adlı kullanıcının navigator grubunda 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 eşzamansızdır. Bu, giriş beklerken kullanıcı arayüzünün engelleme yapmasını önler, ancak seri verileri web sayfası tarafından herhangi bir zamanda alınabileceğinden ve bu verileri dinlemek için bir yönteme ihtiyacımız olduğundan bu önemli bir noktadır.

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 şu 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-seri çipi ile ana işlemci arasında 9600 baud bağlantısı kullanır.

Ayrıca, Bağlan düğmesini de bağlayıp kullanıcı tıkladığında connect() komutunu çağıralı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, bir seri cihaza bağlı olduğunuzu belirten bir simge görürsünüz:

d9d0d3966960aeab.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ğimizden, bunu bir metin kod çözücüden faydalanacağız. Sonra, bir okuyucu alıp okuma döngüsünü başlatacağı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 veri geldiğinde okuyucu iki özellik döndürür: value ve done boole. 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:

93494fd58ea835eb.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 almaya ek olarak, bağlantı noktasına veri göndermek de istiyoruz. Giriş akışında olduğu gibi yalnızca çıkış akışı üzerinden micro:bit'e metin göndereceğiz.

Önce metin kodlayıcı akışı oluşturun ve akışı port.writeable öğesine bağlayı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ır, micro:bit'e gönderilen komutu değerlendirmesini bildirmek için bir 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 karakterlerin tekrarlanmasını durdurmak için CTRL-C tuşlarına basarak 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:

a13187e7e6260f7f.png

5. LED matrisini kontrol etme

Matris ızgara dizesini oluşturma

micro:bit üzerindeki LED matrisini kontrol etmek için show() çağrısını yapmamı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. Onay kutularının sırası matristeki LED'lerin sırasının tersi olduğundan 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ı işaretleyin

Ardından, onay kutularındaki değişiklikleri dinlememiz ve bu değişikliklerin olması durumunda bu bilgiyi 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ırlayalım, böylece mutlu bir yüz gösterebiliriz. drawGrid() işlevi zaten sağlanmış. Bu işlev, sendGrid() işlevine 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

Sayfa artık micro:bit ile bir bağlantı açtığında mutlu bir yüz gönderir. Onay kutuları tıklandığında, 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 üzerinde, LED matrisinin her iki tarafında bir düğme olmak üzere iki 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 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 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

Bağlantı kurulduğunda mutlu bir yüz göstermenin yanı sıra, micro:bit üzerindeki düğmelerden birine bastığınızda 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: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üşüm 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, akışlar çok faydalı olabilir.

Uygulama şu anda gelen akışı geldiğinde (readLoop) yazdırıyor. Çoğu durumda, her karakter kendi satırındadır, ancak bu pek faydalı değildir. İdeal olarak, akışın ayrı satırlara ayrıştırılması ve her mesaj kendi satırı olarak gösterilmesi gerekir.

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

Bunu yapmak için gelen akışın ayrıştırılmasını ve ayrıştırılmış verilerin döndürülmesini 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's Streams API kavramları bölümüne bakın.

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ış tarafından her yeni veri alındığı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 öğesine yeni veriler ekleyeceğiz ve ardından container içinde satır sonu olup olmadığını kontrol edeceğiz. Varsa diziye bölün ve satırlar boyunca yinelenir. Ayrıştırılmış satırları göndermek için controller.enqueue() çağrısı yapın.

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 bir TextDecoderStream aracılığıyla 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'teki düğmelere basın ve aşağıdakine benzer bir sonuç aldığınızı doğrulayın:

6c2193880c748412.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 dosyasının her zaman yalnızca tek bir satırda gönderileceğini bildiğimizden bu yöntem, JSONTransformer dosyamızı 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] basılı olduğunu 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öreceksiniz.
  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 matristeki 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. Mikro:bit üzerindeki 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ı kaldırma 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ı dilediğ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öreceksiniz
  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 Serial API ile ilgili son gelişmeler ve Chrome ekibinin üzerinde çalıştığı diğer heyecan verici yeni web özellikleri için https://goo.gle/fugu-api-tracker adresine göz atın.