อ่านและเขียนไปยังพอร์ตอนุกรม

Web Serial API ช่วยให้เว็บไซต์สื่อสารกับอุปกรณ์ซีเรียลได้

François Beaufort
François Beaufort

Web Serial API คืออะไร

พอร์ตอนุกรมคืออินเทอร์เฟซการสื่อสารแบบ 2 ทิศทางที่อนุญาตให้ส่งและรับข้อมูลทีละไบต์

Web Serial API เป็นวิธีที่ช่วยให้เว็บไซต์อ่านและเขียนไปยังอุปกรณ์ซีเรียลด้วย JavaScript ได้ อุปกรณ์ซีเรียลจะเชื่อมต่อผ่านพอร์ตซีเรียลในระบบของผู้ใช้ หรือผ่านอุปกรณ์ USB และบลูทูธแบบถอดได้ซึ่งจําลองพอร์ตซีเรียล

กล่าวคือ Web Serial API เป็นสะพานเชื่อมระหว่างเว็บกับโลกแห่งความเป็นจริงโดยอนุญาตให้เว็บไซต์สื่อสารกับอุปกรณ์ซีเรียล เช่น ไมโครคอนโทรลเลอร์และเครื่องพิมพ์ 3 มิติ

นอกจากนี้ API นี้ยังทำงานร่วมกับ WebUSB ได้เป็นอย่างดี เนื่องจากระบบปฏิบัติการกำหนดให้แอปพลิเคชันสื่อสารกับพอร์ตอนุกรมบางพอร์ตโดยใช้ API อนุกรมระดับสูงขึ้นแทน API USB ระดับต่ำ

กรณีการใช้งานที่แนะนํา

ผู้ใช้เชื่อมต่ออุปกรณ์ต่อพ่วงกับคอมพิวเตอร์ในภาคการศึกษา ภาคอุตสาหกรรม และภาคงานอดิเรก อุปกรณ์เหล่านี้มักควบคุมโดยไมโครคอนโทรลเลอร์ผ่านการเชื่อมต่อแบบอนุกรมที่ซอฟต์แวร์ที่กำหนดเองใช้ ซอฟต์แวร์ที่กำหนดเองบางอย่างสำหรับควบคุมอุปกรณ์เหล่านี้สร้างขึ้นด้วยเทคโนโลยีเว็บ

ในบางกรณี เว็บไซต์จะสื่อสารกับอุปกรณ์ผ่านตัวแทนแอปพลิเคชันที่ผู้ใช้ติดตั้งด้วยตนเอง ส่วนแอปพลิเคชันอื่นๆ จะส่งในแอปพลิเคชันที่แพ็กเกจไว้ผ่านเฟรมเวิร์ก เช่น Electron และสำหรับกรณีอื่นๆ ผู้ใช้จะต้องดำเนินการขั้นตอนเพิ่มเติม เช่น การคัดลอกแอปพลิเคชันที่คอมไพล์แล้วไปยังอุปกรณ์ผ่านแฟลชไดรฟ์ USB

ในทุกกรณีเหล่านี้ ประสบการณ์ของผู้ใช้จะดีขึ้นด้วยการสื่อสารโดยตรงระหว่างเว็บไซต์กับอุปกรณ์ที่ควบคุม

สถานะปัจจุบัน

ขั้นตอน สถานะ
1. สร้างคําอธิบาย เสร็จสมบูรณ์
2. สร้างข้อกำหนดคร่าวๆ เบื้องต้น เสร็จสมบูรณ์
3. รวบรวมความคิดเห็นและปรับปรุงการออกแบบ เสร็จสมบูรณ์
4. ช่วงทดลองใช้จากต้นทาง เสร็จสมบูรณ์
5. เปิดตัว เสร็จสมบูรณ์

การใช้ Web Serial API

การตรวจหาองค์ประกอบ

หากต้องการตรวจสอบว่าระบบรองรับ Web Serial API หรือไม่ ให้ใช้

if ("serial" in navigator) {
  // The Web Serial API is supported.
}

เปิดพอร์ตอนุกรม

Web Serial API ออกแบบมาให้ทำงานแบบไม่พร้อมกัน ซึ่งจะช่วยป้องกันไม่ให้ UI ของเว็บไซต์บล็อกเมื่อรออินพุต ซึ่งสำคัญเนื่องจากระบบอาจได้รับข้อมูลอนุกรมได้ทุกเมื่อ จึงต้องมีวิธีรับฟังข้อมูล

หากต้องการเปิดพอร์ตอนุกรม ให้เข้าถึงออบเจ็กต์ SerialPort ก่อน ในกรณีนี้ คุณสามารถขอให้ผู้ใช้เลือกพอร์ตซีเรียลรายการเดียวโดยเรียกใช้ navigator.serial.requestPort() เพื่อตอบสนองต่อท่าทางสัมผัสของผู้ใช้ เช่น การสัมผัสหรือการคลิกเมาส์ หรือเลือกพอร์ตจาก navigator.serial.getPorts() ซึ่งจะแสดงรายการพอร์ตซีเรียลที่เว็บไซต์ได้รับสิทธิ์เข้าถึง

document.querySelector('button').addEventListener('click', async () => {
  // Prompt user to select any serial port.
  const port = await navigator.serial.requestPort();
});
// Get all serial ports the user has previously granted the website access to.
const ports = await navigator.serial.getPorts();

ฟังก์ชัน navigator.serial.requestPort() จะรับออบเจ็กต์ลิเทอรัลที่ไม่บังคับซึ่งกำหนดตัวกรอง ซึ่งจะใช้จับคู่อุปกรณ์ซีเรียลที่เชื่อมต่อผ่าน USB กับผู้ให้บริการ USB (usbVendorId) ที่จำเป็นและตัวระบุผลิตภัณฑ์ USB (usbProductId) ที่ไม่บังคับ

// Filter on devices with the Arduino Uno USB Vendor/Product IDs.
const filters = [
  { usbVendorId: 0x2341, usbProductId: 0x0043 },
  { usbVendorId: 0x2341, usbProductId: 0x0001 }
];

// Prompt user to select an Arduino Uno device.
const port = await navigator.serial.requestPort({ filters });

const { usbProductId, usbVendorId } = port.getInfo();
ภาพหน้าจอของข้อความแจ้งพอร์ตอนุกรมในเว็บไซต์
พรอมต์ของผู้ใช้สำหรับเลือก BBC micro:bit

การเรียกใช้ requestPort() จะแจ้งให้ผู้ใช้เลือกอุปกรณ์และส่งคืนออบเจ็กต์ SerialPort เมื่อมีออบเจ็กต์ SerialPort แล้ว การเรียกใช้ port.open() ด้วยอัตรารับส่งข้อมูลที่ต้องการจะเปิดพอร์ตอนุกรม baudRate dictionary member จะระบุความเร็วในการส่งข้อมูลผ่านบรรทัดซีเรียล โดยอัตราบิตจะแสดงเป็นหน่วยบิตต่อวินาที (bps) ตรวจสอบค่าที่ถูกต้องในเอกสารประกอบของอุปกรณ์ เนื่องจากข้อมูลทั้งหมดที่คุณส่งและรับจะเป็นคำที่ไม่มีความหมายหากระบุค่านี้ไม่ถูกต้อง สำหรับอุปกรณ์ USB และบลูทูธบางอย่างที่จำลองพอร์ตอนุกรม ระบบอาจกำหนดค่านี้เป็นค่าใดก็ได้อย่างปลอดภัย เนื่องจากการจำลองจะไม่สนใจค่านี้

// Prompt user to select any serial port.
const port = await navigator.serial.requestPort();

// Wait for the serial port to open.
await port.open({ baudRate: 9600 });

นอกจากนี้ คุณยังระบุตัวเลือกใดก็ได้ด้านล่างเมื่อเปิดพอร์ตซีเรียล ตัวเลือกเหล่านี้เป็นตัวเลือกที่ไม่บังคับและมีค่าเริ่มต้นที่สะดวก

  • dataBits: จำนวนบิตข้อมูลต่อเฟรม (7 หรือ 8)
  • stopBits: จํานวนบิตหยุดที่ท้ายเฟรม (1 หรือ 2)
  • parity: โหมดพาริตี ("none", "even" หรือ "odd")
  • bufferSize: ขนาดของบัฟเฟอร์แบบอ่านและเขียนที่ควรสร้าง (ต้องเล็กกว่า 16 MB)
  • flowControl: โหมดการควบคุมโฟลว์ ("none" หรือ "hardware")

อ่านจากพอร์ตอนุกรม

สตรีมอินพุตและเอาต์พุตใน Web Serial API จะได้รับการจัดการโดย Streams API

หลังจากสร้างการเชื่อมต่อพอร์ตอนุกรม พร็อพเพอร์ตี้ readable และ writable จากออบเจ็กต์ SerialPort จะแสดงผล ReadableStream และ WritableStream ซึ่งจะใช้รับข้อมูลจากและส่งข้อมูลไปยังอุปกรณ์ซีเรียล ทั้ง 2 อินสแตนซ์ใช้อินสแตนซ์ Uint8Array สำหรับการโอนข้อมูล

เมื่อข้อมูลใหม่มาจากอุปกรณ์ซีเรียล port.readable.getReader().read() จะแสดงผลพร็อพเพอร์ตี้ 2 รายการแบบไม่พร้อมกัน ได้แก่ value และบูลีน done หาก done เป็น "จริง" แสดงว่าพอร์ตอนุกรมถูกปิดหรือไม่มีข้อมูลเข้ามาอีก การเรียกใช้ port.readable.getReader() จะสร้างโปรแกรมอ่านและล็อก readable ไว้กับโปรแกรมอ่าน ขณะที่ readable ล็อกอยู่ พอร์ตซีเรียลจะปิดไม่ได้

const reader = port.readable.getReader();

// Listen to data coming from the serial device.
while (true) {
  const { value, done } = await reader.read();
  if (done) {
    // Allow the serial port to be closed later.
    reader.releaseLock();
    break;
  }
  // value is a Uint8Array.
  console.log(value);
}

ข้อผิดพลาดในการอ่านพอร์ตอนุกรมที่ไม่ร้ายแรงอาจเกิดขึ้นได้ภายใต้เงื่อนไขบางอย่าง เช่น การบัฟเฟอร์ล้น ข้อผิดพลาดในการจัดเฟรม หรือข้อผิดพลาดเกี่ยวกับความเท่าเทียม การควบคุมเหล่านั้นจะเป็นข้อยกเว้นและจับได้โดยการเพิ่มอีกวนซ้ำนอกเหนือจาก URL ก่อนหน้าที่ตรวจสอบ port.readable การดำเนินการนี้ได้ผลเนื่องจากระบบจะสร้าง ReadableStream ใหม่โดยอัตโนมัติตราบใดที่ข้อผิดพลาดไม่ใช่ข้อผิดพลาดร้ายแรง หากเกิดข้อผิดพลาดร้ายแรง เช่น มีการนำอุปกรณ์ซีเรียลออก port.readable จะกลายเป็นค่าว่าง

while (port.readable) {
  const reader = port.readable.getReader();

  try {
    while (true) {
      const { value, done } = await reader.read();
      if (done) {
        // Allow the serial port to be closed later.
        reader.releaseLock();
        break;
      }
      if (value) {
        console.log(value);
      }
    }
  } catch (error) {
    // TODO: Handle non-fatal read error.
  }
}

หากอุปกรณ์ซีเรียลส่งข้อความกลับมา คุณสามารถส่งผ่าน port.readable ผ่าน TextDecoderStream ดังที่แสดงด้านล่าง TextDecoderStream คือ สตรีมการเปลี่ยนรูปแบบ ที่ดึงข้อมูล Uint8Array ทั้งหมดและแปลงเป็นสตริง

const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
const reader = textDecoder.readable.getReader();

// Listen to data coming from the serial device.
while (true) {
  const { value, done } = await reader.read();
  if (done) {
    // Allow the serial port to be closed later.
    reader.releaseLock();
    break;
  }
  // value is a string.
  console.log(value);
}

คุณสามารถควบคุมวิธีจัดสรรหน่วยความจำเมื่อคุณอ่านจากสตรีมโดยใช้โปรแกรมอ่าน "Bring Your Own Buffer" โทรหา port.readable.getReader({ mode: "byob" }) เพื่อรับอินเทอร์เฟซ ReadableStreamBYOBReader และระบุ ArrayBuffer ของคุณเองเมื่อโทรหา read() โปรดทราบว่า Web Serial API รองรับฟีเจอร์นี้ใน Chrome เวอร์ชัน 106 ขึ้นไป

try {
  const reader = port.readable.getReader({ mode: "byob" });
  // Call reader.read() to read data into a buffer...
} catch (error) {
  if (error instanceof TypeError) {
    // BYOB readers are not supported.
    // Fallback to port.readable.getReader()...
  }
}

ต่อไปนี้คือตัวอย่างวิธีใช้บัฟเฟอร์ออกจาก value.buffer ซ้ำ

const bufferSize = 1024; // 1kB
let buffer = new ArrayBuffer(bufferSize);

// Set `bufferSize` on open() to at least the size of the buffer.
await port.open({ baudRate: 9600, bufferSize });

const reader = port.readable.getReader({ mode: "byob" });
while (true) {
  const { value, done } = await reader.read(new Uint8Array(buffer));
  if (done) {
    break;
  }
  buffer = value.buffer;
  // Handle `value`.
}

ต่อไปนี้เป็นตัวอย่างวิธีอ่านข้อมูลจำนวนหนึ่งจากพอร์ตซีเรียล

async function readInto(reader, buffer) {
  let offset = 0;
  while (offset < buffer.byteLength) {
    const { value, done } = await reader.read(
      new Uint8Array(buffer, offset)
    );
    if (done) {
      break;
    }
    buffer = value.buffer;
    offset += value.byteLength;
  }
  return buffer;
}

const reader = port.readable.getReader({ mode: "byob" });
let buffer = new ArrayBuffer(512);
// Read the first 512 bytes.
buffer = await readInto(reader, buffer);
// Then read the next 512 bytes.
buffer = await readInto(reader, buffer);

เขียนไปยังพอร์ตอนุกรม

หากต้องการส่งข้อมูลไปยังอุปกรณ์ซีเรียล ให้ส่งข้อมูลไปยัง port.writable.getWriter().write() คุณต้องโทรหา releaseLock() ใน port.writable.getWriter() เพื่อให้พอร์ตอนุกรมปิดในภายหลัง

const writer = port.writable.getWriter();

const data = new Uint8Array([104, 101, 108, 108, 111]); // hello
await writer.write(data);


// Allow the serial port to be closed later.
writer.releaseLock();

ส่งข้อความไปยังอุปกรณ์ผ่าน TextEncoderStream ที่ส่งผ่านไปยัง port.writable ดังที่แสดงด้านล่าง

const textEncoder = new TextEncoderStream();
const writableStreamClosed = textEncoder.readable.pipeTo(port.writable);

const writer = textEncoder.writable.getWriter();

await writer.write("hello");

ปิดพอร์ตอนุกรม

port.close() จะปิดพอร์ตอนุกรมหากสมาชิก readable และ writable ปลดล็อกอยู่ ซึ่งหมายความว่ามีการเรียกใช้ releaseLock() สำหรับโปรแกรมอ่านและโปรแกรมเขียนที่เกี่ยวข้อง

await port.close();

อย่างไรก็ตาม เมื่ออ่านข้อมูลจากอุปกรณ์ซีเรียลอย่างต่อเนื่องโดยใช้ลูป port.readable จะล็อกอยู่เสมอจนกว่าจะพบข้อผิดพลาด ในกรณีนี้ การเรียกใช้ reader.cancel() จะบังคับให้ reader.read() แก้ปัญหากับ { value: undefined, done: true } ทันที และทำให้ลูปเรียกใช้ reader.releaseLock() ได้

// Without transform streams.

let keepReading = true;
let reader;

async function readUntilClosed() {
  while (port.readable && keepReading) {
    reader = port.readable.getReader();
    try {
      while (true) {
        const { value, done } = await reader.read();
        if (done) {
          // reader.cancel() has been called.
          break;
        }
        // value is a Uint8Array.
        console.log(value);
      }
    } catch (error) {
      // Handle error...
    } finally {
      // Allow the serial port to be closed later.
      reader.releaseLock();
    }
  }

  await port.close();
}

const closedPromise = readUntilClosed();

document.querySelector('button').addEventListener('click', async () => {
  // User clicked a button to close the serial port.
  keepReading = false;
  // Force reader.read() to resolve immediately and subsequently
  // call reader.releaseLock() in the loop example above.
  reader.cancel();
  await closedPromise;
});

การปิดพอร์ตอนุกรมจะซับซ้อนมากขึ้นเมื่อใช้การแปลงสตรีม โทรหา reader.cancel() เหมือนเดิม จากนั้นโทรหา writer.close() และ port.close() ซึ่งจะทำให้เกิดข้อผิดพลาดผ่านสตรีมการเปลี่ยนรูปแบบไปยังพอร์ตอนุกรมที่อยู่เบื้องหลัง เนื่องจากการนำข้อผิดพลาดไปข้างหน้าจะไม่เกิดขึ้นทันที คุณจึงต้องใช้สัญญา readableStreamClosed และ writableStreamClosed ที่สร้างขึ้นก่อนหน้านี้เพื่อตรวจหาเมื่อ port.readable และ port.writable ได้รับการปลดล็อกแล้ว การยกเลิก reader จะทําให้สตรีมหยุดลง คุณจึงต้องจับข้อผิดพลาดที่เกิดขึ้นและละเว้น

// With transform streams.

const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
const reader = textDecoder.readable.getReader();

// Listen to data coming from the serial device.
while (true) {
  const { value, done } = await reader.read();
  if (done) {
    reader.releaseLock();
    break;
  }
  // value is a string.
  console.log(value);
}

const textEncoder = new TextEncoderStream();
const writableStreamClosed = textEncoder.readable.pipeTo(port.writable);

reader.cancel();
await readableStreamClosed.catch(() => { /* Ignore the error */ });

writer.close();
await writableStreamClosed;

await port.close();

ฟังการเชื่อมต่อและการตัดการเชื่อมต่อ

หากอุปกรณ์ USB ได้รับพอร์ตอนุกรม อุปกรณ์นั้นอาจเชื่อมต่อหรือยกเลิกการเชื่อมต่อจากระบบ เมื่อได้รับสิทธิ์เข้าถึงพอร์ตอนุกรม เว็บไซต์ควรตรวจสอบเหตุการณ์ connect และ disconnect

navigator.serial.addEventListener("connect", (event) => {
  // TODO: Automatically open event.target or warn user a port is available.
});

navigator.serial.addEventListener("disconnect", (event) => {
  // TODO: Remove |event.target| from the UI.
  // If the serial port was opened, a stream error would be observed as well.
});

จัดการสัญญาณ

หลังจากสร้างการเชื่อมต่อพอร์ตอนุกรมแล้ว คุณสามารถค้นหาและตั้งค่าสัญญาณที่แสดงโดยพอร์ตอนุกรมอย่างชัดเจนเพื่อการตรวจหาอุปกรณ์และการควบคุมโฟลว์ สัญญาณเหล่านี้จะกําหนดเป็นค่าบูลีน ตัวอย่างเช่น อุปกรณ์บางอย่างเช่น Arduino จะเข้าสู่โหมดการเขียนโปรแกรมหากมีการเปิด/ปิดสัญญาณ Data Terminal Ready (DTR)

การตั้งค่าสัญญาณเอาต์พุตและการรับสัญญาณอินพุตทำได้โดยเรียกใช้ port.setSignals() และ port.getSignals() ตามลำดับ ดูตัวอย่างการใช้งานด้านล่าง

// Turn off Serial Break signal.
await port.setSignals({ break: false });

// Turn on Data Terminal Ready (DTR) signal.
await port.setSignals({ dataTerminalReady: true });

// Turn off Request To Send (RTS) signal.
await port.setSignals({ requestToSend: false });
const signals = await port.getSignals();
console.log(`Clear To Send:       ${signals.clearToSend}`);
console.log(`Data Carrier Detect: ${signals.dataCarrierDetect}`);
console.log(`Data Set Ready:      ${signals.dataSetReady}`);
console.log(`Ring Indicator:      ${signals.ringIndicator}`);

การเปลี่ยนรูปแบบสตรีม

เมื่อได้รับข้อมูลจากอุปกรณ์ซีเรียล คุณไม่จำเป็นต้องรับข้อมูลทั้งหมดในคราวเดียว โดยอาจมีการแบ่งออกเป็นกลุ่มๆ โปรดดูข้อมูลเพิ่มเติมที่หัวข้อแนวคิดเกี่ยวกับ Streams API

วิธีจัดการปัญหานี้คือใช้สตรีมการเปลี่ยนรูปแบบในตัวบางรายการ เช่น TextDecoderStream หรือสร้างสตรีมการเปลี่ยนรูปแบบของคุณเองซึ่งช่วยให้คุณแยกวิเคราะห์สตรีมขาเข้าและแสดงผลข้อมูลที่แยกวิเคราะห์แล้วได้ สตรีมการเปลี่ยนรูปแบบจะอยู่ระหว่างอุปกรณ์ซีเรียลกับลูปการอ่านที่ใช้สตรีม โดยสามารถทําการเปลี่ยนรูปแบบแบบใดก็ได้ก่อนที่จะใช้ข้อมูล เปรียบได้กับเส้นประกอบ นั่นคือเหมือนกับวิดเจ็ตที่ค่อยๆ เลื่อนลงทีละขั้น แต่ละขั้นตอนในบรรทัดจะปรับเปลี่ยนวิดเจ็ต เพื่อให้เมื่อไปถึงปลายทางสุดท้ายแล้ว วิดเจ็ตที่ทำงานได้อย่างสมบูรณ์

รูปภาพโรงงานผลิตเครื่องบิน
โรงงานผลิตเครื่องบิน Castle Bromwich ในสมัยสงครามโลกครั้งที่ 2

เช่น ลองนึกถึงวิธีสร้างคลาสสตรีมการเปลี่ยนรูปแบบที่ใช้สตรีมและแบ่งสตรีมตามตัวแบ่งบรรทัด ระบบจะเรียกใช้เมธอด transform() ทุกครั้งที่สตรีมได้รับข้อมูลใหม่ โดยสามารถจัดคิวข้อมูลหรือบันทึกไว้ใช้ในภายหลังก็ได้ ระบบจะเรียกเมธอด flush() เมื่อปิดสตรีม และจะจัดการข้อมูลที่ยังไม่ได้ประมวลผล

หากต้องการใช้คลาสสตรีมการเปลี่ยนรูปแบบ คุณต้องส่งผ่านสตรีมขาเข้าผ่านคลาสนี้ ในตัวอย่างโค้ดที่ 3 ในส่วนอ่านจากพอร์ตอนุกรม สตรีมอินพุตเดิมได้รับการส่งผ่านผ่าน TextDecoderStream เท่านั้น เราจึงต้องเรียกใช้ pipeThrough() เพื่อส่งผ่านสตรีมผ่าน LineBreakTransformer ใหม่

class LineBreakTransformer {
  constructor() {
    // A container for holding stream data until a new line.
    this.chunks = "";
  }

  transform(chunk, controller) {
    // Append new chunks to existing chunks.
    this.chunks += chunk;
    // For each line breaks in chunks, send the parsed lines out.
    const lines = this.chunks.split("\r\n");
    this.chunks = lines.pop();
    lines.forEach((line) => controller.enqueue(line));
  }

  flush(controller) {
    // When the stream is closed, flush any remaining chunks out.
    controller.enqueue(this.chunks);
  }
}
const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
const reader = textDecoder.readable
  .pipeThrough(new TransformStream(new LineBreakTransformer()))
  .getReader();

หากต้องการแก้ไขข้อบกพร่องเกี่ยวกับการสื่อสารของอุปกรณ์ซีเรียล ให้ใช้เมธอด tee() ของ port.readable เพื่อแยกสตรีมไปยังหรือจากอุปกรณ์ซีเรียล สตรีม 2 รายการที่สร้างไว้จะใช้แยกกันได้ ซึ่งจะช่วยให้คุณพิมพ์สตรีมหนึ่งไปยังคอนโซลเพื่อตรวจสอบได้

const [appReadable, devReadable] = port.readable.tee();

// You may want to update UI with incoming data from appReadable
// and log incoming data in JS console for inspection from devReadable.

เพิกถอนสิทธิ์เข้าถึงพอร์ตอนุกรม

เว็บไซต์สามารถล้างสิทธิ์เข้าถึงพอร์ตอนุกรมที่ไม่ต้องการเก็บรักษาอีกต่อไปได้โดยเรียกใช้ forget() ในอินสแตนซ์ SerialPort ตัวอย่างเช่น เว็บแอปพลิเคชันด้านการศึกษาที่ใช้ในคอมพิวเตอร์ที่ใช้ร่วมกันกับอุปกรณ์จํานวนมาก สิทธิ์ที่ผู้ใช้สร้างขึ้นจํานวนมากจะทําให้ประสบการณ์ของผู้ใช้แย่ลง

// Voluntarily revoke access to this serial port.
await port.forget();

เนื่องจาก forget() พร้อมใช้งานใน Chrome 103 ขึ้นไป โปรดตรวจสอบว่าฟีเจอร์นี้รองรับรายการต่อไปนี้หรือไม่

if ("serial" in navigator && "forget" in SerialPort.prototype) {
  // forget() is supported.
}

เคล็ดลับสำหรับนักพัฒนาซอฟต์แวร์

การแก้ไขข้อบกพร่องของ Web Serial API ใน Chrome ทำได้ง่ายด้วยหน้าภายใน ซึ่งabout://device-logคุณสามารถดูเหตุการณ์ทั้งหมดที่เกี่ยวข้องกับอุปกรณ์ซีเรียลได้ในที่เดียว

ภาพหน้าจอของหน้าภายในสำหรับการแก้ไขข้อบกพร่องของ Web Serial API
หน้าภายในใน Chrome สำหรับการแก้ไขข้อบกพร่องของ Web Serial API

Codelab

ใน Google Developer Codelab คุณจะใช้ Web Serial API เพื่อโต้ตอบกับบอร์ด BBC micro:bit เพื่อแสดงรูปภาพบนเมทริกซ์ LED 5x5 ได้

การสนับสนุนเบราว์เซอร์

Web Serial API พร้อมใช้งานในแพลตฟอร์มเดสก์ท็อปทุกแพลตฟอร์ม (ChromeOS, Linux, macOS และ Windows) ใน Chrome 89

ใยโพลีเอสเตอร์

ใน Android คุณจะรองรับพอร์ตอนุกรมที่ใช้ USB ได้โดยใช้ WebUSB API และ Serial API polyfill โพลีฟีลนี้จํากัดไว้สําหรับฮาร์ดแวร์และแพลตฟอร์มที่เข้าถึงอุปกรณ์ผ่าน WebUSB API ได้ เนื่องจากยังไม่มีไดรเวอร์อุปกรณ์ในตัวอ้างสิทธิ์

ความปลอดภัยและความเป็นส่วนตัว

ผู้เขียนข้อมูลจำเพาะได้ออกแบบและใช้งาน Web Serial API โดยใช้หลักการสำคัญที่ระบุไว้ในการควบคุมการเข้าถึงฟีเจอร์แพลตฟอร์มเว็บที่มีประสิทธิภาพ ซึ่งรวมถึงการควบคุมผู้ใช้ ความโปร่งใส และการยศาสตร์ ความสามารถในการใช้ API นี้ถูกจำกัดโดยรูปแบบสิทธิ์ที่อนุญาตให้เข้าถึงอุปกรณ์ซีเรียลได้ครั้งละ 1 เครื่องเท่านั้น ผู้ใช้ต้องดำเนินการตามขั้นตอนเพื่อเลือกอุปกรณ์ซีเรียลที่ต้องการเพื่อตอบสนองต่อข้อความแจ้ง

หากต้องการทำความเข้าใจข้อเสียด้านความปลอดภัย โปรดดูส่วนความปลอดภัยและความเป็นส่วนตัวของคำอธิบาย Web Serial API

ความคิดเห็น

ทีม Chrome อยากทราบความคิดเห็นและประสบการณ์ของคุณเกี่ยวกับ Web Serial API

บอกเราเกี่ยวกับการออกแบบ API

มีสิ่งใดเกี่ยวกับ API ที่ไม่ทำงานตามที่คาดไว้ไหม หรือมีเมธอดหรือพร็อพเพอร์ตี้ที่ขาดหายไปซึ่งคุณต้องนำไปใช้กับไอเดียของคุณ

ยื่นข้อมูลจำเพาะในที่เก็บ GitHub ของ Web Serial API หรือเพิ่มความคิดของคุณลงในปัญหาที่มีอยู่

รายงานปัญหาเกี่ยวกับการติดตั้งใช้งาน

คุณพบข้อบกพร่องในการติดตั้งใช้งาน Chrome ไหม หรือการใช้งานแตกต่างจากข้อกําหนดหรือไม่

รายงานข้อบกพร่องที่ https://new.crbug.com อย่าลืมระบุรายละเอียดให้มากที่สุด ระบุวิธีการง่ายๆ ในการทําให้เกิดข้อบกพร่องซ้ำ และตั้งค่าคอมโพเนนต์เป็น Blink>Serial Glitch เหมาะอย่างยิ่งสำหรับการแชร์การจำลองข้อบกพร่องที่รวดเร็วและง่ายดาย

แสดงการสนับสนุน

คุณวางแผนที่จะใช้ Web Serial API ไหม การสนับสนุนแบบสาธารณะของคุณจะช่วยให้ทีม Chrome จัดลําดับความสําคัญของฟีเจอร์ต่างๆ และแสดงให้เห็นว่าการสนับสนุนฟีเจอร์เหล่านี้สำคัญเพียงใดต่อผู้ให้บริการเบราว์เซอร์รายอื่นๆ

ทวีตถึง @ChromiumDev โดยใช้แฮชแท็ก #SerialAPI และแจ้งให้เราทราบว่าคุณใช้ฟีเจอร์นี้ที่ไหนและอย่างไร

ลิงก์ที่มีประโยชน์

เดโม

ขอขอบคุณ

ขอขอบคุณ Reilly Grant และ Joe Medley ที่ตรวจสอบบทความนี้ รูปภาพโรงงานผลิตเครื่องบินโดย Birmingham Museums Trust ใน Unsplash