किसी सीरियल पोर्ट से पढ़ें और उस पर लिखें

Web Serial API की मदद से, वेबसाइटें सीरियल डिवाइसों से कम्यूनिकेट कर सकती हैं.

François Beaufort
François Beaufort

Web Serial API क्या है?

सीरियल पोर्ट, दोनों दिशाओं में कम्यूनिकेशन करने वाला इंटरफ़ेस होता है. इसकी मदद से, डेटा को बाइट के हिसाब से भेजा और पाया जा सकता है.

Web Serial API की मदद से, वेबसाइटें JavaScript का इस्तेमाल करके सीरियल डिवाइस से डेटा पढ़ सकती हैं और उस पर डेटा लिख सकती हैं. सीरियल डिवाइस, उपयोगकर्ता के सिस्टम पर मौजूद सीरियल पोर्ट या हटाने योग्य यूएसबी और ब्लूटूथ डिवाइसों के ज़रिए कनेक्ट किए जाते हैं. ये डिवाइस, सीरियल पोर्ट की तरह काम करते हैं.

दूसरे शब्दों में कहें, तो Web Serial API, वेब और फ़िज़िकल दुनिया के बीच पुल का काम करता है. यह वेबसाइटों को सीरियल डिवाइसों, जैसे कि माइक्रोकंट्रोलर और 3D प्रिंटर के साथ कम्यूनिकेट करने की अनुमति देता है.

यह एपीआई, WebUSB के साथ भी काम करता है. ऐसा इसलिए, क्योंकि ऑपरेटिंग सिस्टम को कुछ सीरियल पोर्ट के साथ कम्यूनिकेट करने के लिए, ऐप्लिकेशन को लो-लेवल USB API के बजाय, हायर-लेवल सीरियल API का इस्तेमाल करना पड़ता है.

इस्तेमाल के सुझाए गए उदाहरण

शिक्षा, शौक, और उद्योग के क्षेत्रों में, उपयोगकर्ता अपने कंप्यूटर से पेरिफ़ेरल डिवाइस कनेक्ट करते हैं. इन डिवाइसों को अक्सर कस्टम सॉफ़्टवेयर के ज़रिए इस्तेमाल किए जाने वाले सीरियल कनेक्शन की मदद से, माइक्रोकंट्रोलर कंट्रोल करते हैं. इन डिवाइसों को कंट्रोल करने के लिए, वेब टेक्नोलॉजी का इस्तेमाल करके कुछ कस्टम सॉफ़्टवेयर बनाए गए हैं:

कुछ मामलों में, वेबसाइटें डिवाइस के साथ किसी एजेंट ऐप्लिकेशन के ज़रिए कम्यूनिकेट करती हैं. इस ऐप्लिकेशन को उपयोगकर्ताओं ने मैन्युअल तरीके से इंस्टॉल किया होता है. अन्य मामलों में, ऐप्लिकेशन को पैकेज किए गए ऐप्लिकेशन के तौर पर डिलीवर किया जाता है. इसके लिए, Electron जैसे फ़्रेमवर्क का इस्तेमाल किया जाता है. वहीं, कुछ मामलों में उपयोगकर्ता को एक और चरण पूरा करना होता है. जैसे, कंपाइल किए गए ऐप्लिकेशन को यूएसबी फ़्लैश ड्राइव के ज़रिए डिवाइस पर कॉपी करना.

इन सभी मामलों में, वेबसाइट और उसे कंट्रोल करने वाले डिवाइस के बीच सीधे तौर पर कम्यूनिकेशन की सुविधा देकर, उपयोगकर्ता अनुभव को बेहतर बनाया जाएगा.

मौजूदा स्थिति

चरण स्थिति
1. एक्सप्लेनर बनाना पूरा हो गया
2. स्पेसिफ़िकेशन का शुरुआती ड्राफ़्ट बनाना पूरा हो गया
3. सुझाव/राय पाना और डिज़ाइन को बेहतर बनाना पूरा हो गया
4. ऑरिजिन ट्रायल पूरा हो गया
5. लॉन्च करें पूरा हो गया

Web Serial API का इस्तेमाल करना

सुविधा का पता लगाना

Web Serial API काम करता है या नहीं, यह देखने के लिए इसका इस्तेमाल करें:

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

सीरियल पोर्ट खोलना

Web Serial API को एसिंक्रोनस तरीके से डिज़ाइन किया गया है. इससे वेबसाइट का यूज़र इंटरफ़ेस (यूआई), इनपुट का इंतज़ार करते समय ब्लॉक नहीं होता. यह ज़रूरी है, क्योंकि सीरियल डेटा कभी भी मिल सकता है. इसलिए, इसे सुनने का तरीका होना चाहिए.

किसी सीरियल पोर्ट को खोलने के लिए, पहले 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() फ़ंक्शन, फ़िल्टर तय करने वाले ऑब्जेक्ट लिटरल को इनपुट के तौर पर लेता है. इनका इस्तेमाल, यूएसबी से कनेक्ट किए गए किसी भी सीरियल डिवाइस को, यूएसबी के ज़रूरी वेंडर (usbVendorId) और यूएसबी के वैकल्पिक प्रॉडक्ट आइडेंटिफ़ायर (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 डिक्शनरी मेंबर यह तय करता है कि सीरियल लाइन पर डेटा कितनी तेज़ी से भेजा जाता है. इसे बिट्स-पर-सेकंड (बीपीएस) की इकाइयों में दिखाया जाता है. अपने डिवाइस के दस्तावेज़ में सही वैल्यू देखें. अगर इसे गलत तरीके से सेट किया गया है, तो भेजा और पाया गया सारा डेटा समझ से बाहर होगा. कुछ यूएसबी और ब्लूटूथ डिवाइसों के लिए, इस वैल्यू को किसी भी वैल्यू पर सेट किया जा सकता है. ये डिवाइस, सीरियल पोर्ट की तरह काम करते हैं. ऐसा इसलिए, क्योंकि इस वैल्यू को डिवाइस के सीरियल पोर्ट की तरह काम करने की सुविधा अनदेखा कर देती है.

// 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 एमबी से कम होना चाहिए.
  • flowControl: फ़्लो कंट्रोल मोड ("none" या "hardware" में से कोई एक).

किसी सीरियल पोर्ट से डेटा पढ़ना

Web Serial API में इनपुट और आउटपुट स्ट्रीम को Streams API मैनेज करता है.

सीरियल पोर्ट कनेक्शन बन जाने के बाद, SerialPort ऑब्जेक्ट की readable और writable प्रॉपर्टी, ReadableStream और WritableStream दिखाती हैं. इनका इस्तेमाल, सीरियल डिवाइस से डेटा पाने और उसे डेटा भेजने के लिए किया जाएगा. दोनों, डेटा ट्रांसफ़र के लिए Uint8Array इंस्टेंस का इस्तेमाल करते हैं.

सीरियल डिवाइस से नया डेटा मिलने पर, port.readable.getReader().read() दो प्रॉपर्टी को एसिंक्रोनस तरीके से दिखाता है: 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);
}

कुछ मामलों में, सीरियल पोर्ट से डेटा पढ़ने के दौरान ऐसी गड़बड़ियां हो सकती हैं जिनसे सिस्टम पर कोई असर नहीं पड़ता. जैसे, बफ़र ओवरफ़्लो, फ़्रेमिंग से जुड़ी गड़बड़ियां या पैरिटी से जुड़ी गड़बड़ियां. इन्हें अपवाद के तौर पर दिखाया जाता है. साथ ही, इन्हें पिछले लूप के ऊपर एक और लूप जोड़कर पकड़ा जा सकता है. यह लूप, 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" रीडर का इस्तेमाल करके, स्ट्रीम से डेटा पढ़ते समय मेमोरी को मैनेज किया जा सकता है. ReadableStreamBYOBReader इंटरफ़ेस पाने के लिए, port.readable.getReader({ mode: "byob" }) को कॉल करें. साथ ही, read() को कॉल करते समय अपना ArrayBuffer दें. ध्यान दें कि 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");

सीरियल पोर्ट बंद करना

अगर सीरियल पोर्ट के readable और writable सदस्य अनलॉक हैं, तो port.close() सीरियल पोर्ट को बंद कर देता है. इसका मतलब है कि उनके रीडर और राइटर के लिए 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();

कनेक्ट और डिसकनेक्ट करने की सूचनाएं सुनना

अगर सीरियल पोर्ट, यूएसबी डिवाइस से मिलता है, तो उस डिवाइस को सिस्टम से कनेक्ट या डिसकनेक्ट किया जा सकता है. जब वेबसाइट को सीरियल पोर्ट ऐक्सेस करने की अनुमति मिल जाती है, तो उसे 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, डेटा टर्मिनल रेडी (डीटीआर) सिग्नल को टॉगल करने पर प्रोग्रामिंग मोड में चले जाएंगे.

आउटपुट सिग्नल सेट करने और इनपुट सिग्नल पाने के लिए, 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. इसके अलावा, अपनी ट्रांसफ़ॉर्म स्ट्रीम भी बनाई जा सकती है. इससे आपको आने वाली स्ट्रीम को पार्स करने और पार्स किया गया डेटा वापस पाने की सुविधा मिलती है. ट्रांसफ़ॉर्म स्ट्रीम, सीरियल डिवाइस और स्ट्रीम का इस्तेमाल करने वाले रीड लूप के बीच में होती है. यह डेटा इस्तेमाल करने से पहले, कोई भी ट्रांसफ़ॉर्म लागू कर सकता है. इसे असेंबली लाइन की तरह समझें: जैसे-जैसे कोई विजेट लाइन से नीचे आता है, लाइन में मौजूद हर चरण विजेट में बदलाव करता है. इसलिए, जब तक यह अपनी मंज़िल तक पहुंचता है, तब तक यह पूरी तरह से काम करने वाला विजेट बन जाता है.

हवाई जहाज़ बनाने वाली फ़ैक्ट्री की फ़ोटो
द्वितीय विश्व युद्ध के समय की कैसल ब्रोमविच ऐरोप्लेन फ़ैक्ट्री

उदाहरण के लिए, ट्रांसफ़ॉर्म स्ट्रीम क्लास बनाने का तरीका जानें. यह क्लास, स्ट्रीम का इस्तेमाल करती है और लाइन ब्रेक के आधार पर उसे हिस्सों में बांटती है. जब भी स्ट्रीम को नया डेटा मिलता है, तब इसके transform() तरीके को कॉल किया जाता है. यह डेटा को कतार में लगा सकता है या इसे बाद के लिए सेव कर सकता है. स्ट्रीम बंद होने पर, flush() तरीके को कॉल किया जाता है. साथ ही, यह उस डेटा को हैंडल करता है जिसे अब तक प्रोसेस नहीं किया गया है.

ट्रांसफ़ॉर्म स्ट्रीम क्लास का इस्तेमाल करने के लिए, आपको आने वाली स्ट्रीम को इसके ज़रिए पाइप करना होगा. सीरियल पोर्ट से पढ़ना सेक्शन में दिए गए तीसरे कोड के उदाहरण में, ओरिजनल इनपुट स्ट्रीम को सिर्फ़ TextDecoderStream के ज़रिए पाइप किया गया था. इसलिए, हमें इसे अपने नए LineBreakTransformer के ज़रिए पाइप करने के लिए, pipeThrough() को कॉल करना होगा.

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 तरीके का इस्तेमाल करें. इससे सीरियल डिवाइस से आने या जाने वाली स्ट्रीम को अलग-अलग किया जा सकता है. बनाई गई दोनों स्ट्रीम का इस्तेमाल अलग-अलग किया जा सकता है. इससे आपको जांच के लिए, एक स्ट्रीम को कंसोल पर प्रिंट करने की सुविधा मिलती है.

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.

सीरियल पोर्ट का ऐक्सेस रद्द करना

वेबसाइट, सीरियल पोर्ट को ऐक्सेस करने की उन अनुमतियों को हटा सकती है जिन्हें वह अब बनाए नहीं रखना चाहती. इसके लिए, उसे SerialPort इंस्टेंस पर forget() को कॉल करना होगा. उदाहरण के लिए, शिक्षा से जुड़ा कोई वेब ऐप्लिकेशन है, जिसे कई डिवाइसों के साथ शेयर किए गए कंप्यूटर पर इस्तेमाल किया जाता है. ऐसे में, उपयोगकर्ता की जनरेट की गई अनुमतियों की ज़्यादा संख्या होने से, उपयोगकर्ता को खराब अनुभव मिलता है.

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

forget() की सुविधा Chrome 103 या इसके बाद के वर्शन में उपलब्ध है. इसलिए, यह देखें कि यह सुविधा इन पर काम करती है या नहीं:

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

डेवलपर के लिए सलाह

Chrome में Web Serial API को डीबग करना आसान है. इसके लिए, इंटरनल पेज about://device-log का इस्तेमाल किया जा सकता है. यहां आपको सीरियल डिवाइस से जुड़े सभी इवेंट एक ही जगह पर दिखेंगे.

Web Serial API को डीबग करने के लिए, इंटरनल पेज का स्क्रीनशॉट.
Web Serial API को डीबग करने के लिए, Chrome में मौजूद इंटरनल पेज.

कोडलैब (कोड बनाना सीखना)

Google Developer के कोडलैब में, Web Serial API का इस्तेमाल करके BBC micro:bit बोर्ड के साथ इंटरैक्ट किया जाएगा. इससे, बोर्ड की 5x5 एलईडी मैट्रिक्स पर इमेज दिखाई जा सकेंगी.

ब्राउज़र समर्थन

Web Serial API, Chrome 89 में सभी डेस्कटॉप प्लैटफ़ॉर्म (ChromeOS, Linux, macOS, और Windows) पर उपलब्ध है.

पॉलीफ़िल

Android पर, WebUSB API और Serial API polyfill का इस्तेमाल करके, यूएसबी पर आधारित सीरियल पोर्ट के लिए सहायता उपलब्ध कराई जा सकती है. यह पॉलीफ़िल, सिर्फ़ उन हार्डवेयर और प्लैटफ़ॉर्म के लिए उपलब्ध है जहां WebUSB API के ज़रिए डिवाइस को ऐक्सेस किया जा सकता है. ऐसा इसलिए, क्योंकि इसे डिवाइस में पहले से मौजूद ड्राइवर ने क्लेम नहीं किया है.

सुरक्षा और निजता

स्पेसिफ़िकेशन बनाने वालों ने Web Serial API को डिज़ाइन और लागू किया है. इसके लिए, उन्होंने वेब प्लैटफ़ॉर्म की सुविधाओं को ऐक्सेस करने की अनुमति को कंट्रोल करना में बताए गए मुख्य सिद्धांतों का इस्तेमाल किया है. इनमें उपयोगकर्ता का कंट्रोल, पारदर्शिता, और एर्गोनॉमिक्स शामिल हैं. इस एपीआई का इस्तेमाल करने की सुविधा, मुख्य तौर पर अनुमति के मॉडल पर आधारित होती है. यह मॉडल, एक बार में सिर्फ़ एक सीरियल डिवाइस को ऐक्सेस करने की अनुमति देता है. उपयोगकर्ता के प्रॉम्प्ट के जवाब में, उपयोगकर्ता को किसी सीरियल डिवाइस को चुनने के लिए, सक्रिय रूप से कार्रवाई करनी होगी.

सुरक्षा से जुड़े फ़ायदों और नुकसानों के बारे में जानने के लिए, Web Serial API Explainer के सुरक्षा और निजता सेक्शन देखें.

सुझाव/राय दें या शिकायत करें

Chrome टीम, Web Serial API के बारे में आपके विचारों और अनुभवों के बारे में जानना चाहती है.

हमें एपीआई डिज़ाइन के बारे में बताएं

क्या एपीआई के बारे में कुछ ऐसा है जो आपकी उम्मीद के मुताबिक काम नहीं करता? या क्या कोई ऐसा तरीका या प्रॉपर्टी है जो मौजूद नहीं है और आपको अपने आइडिया को लागू करने के लिए उसकी ज़रूरत है?

Web Serial API GitHub repo पर स्पेसिफ़िकेशन से जुड़ी समस्या की शिकायत करें या किसी मौजूदा समस्या के बारे में अपने विचार बताएं.

लागू करने से जुड़ी समस्या की शिकायत करना

क्या आपको Chrome के साथ काम करने वाले किसी एक्सटेंशन में कोई गड़बड़ी मिली? या क्या लागू करने का तरीका, खास जानकारी से अलग है?

https://new.crbug.com पर जाकर, गड़बड़ी की रिपोर्ट करें. इसमें ज़्यादा से ज़्यादा जानकारी शामिल करें. साथ ही, गड़बड़ी को दोहराने के लिए आसान निर्देश दें. इसके अलावा, कॉम्पोनेंट को Blink>Serial पर सेट करें.

क्रिएटर के लिए अपना सपोर्ट दिखाएं

क्या आपको Web Serial API का इस्तेमाल करना है? आपकी सार्वजनिक राय से, Chrome टीम को सुविधाओं को प्राथमिकता देने में मदद मिलती है. साथ ही, इससे अन्य ब्राउज़र बनाने वाली कंपनियों को यह पता चलता है कि इन सुविधाओं को सपोर्ट करना कितना ज़रूरी है.

@ChromiumDev को ट्वीट करें. इसके लिए, हैशटैग #SerialAPI का इस्तेमाल करें. साथ ही, हमें बताएं कि इसका इस्तेमाल कहां और कैसे किया जा रहा है.

मददगार लिंक

डेमो

Acknowledgements

इस लेख की समीक्षा करने के लिए, रेली ग्रांट और जो मेडली का धन्यवाद. बर्मिंघम म्यूज़ियम ट्रस्ट ने Unsplash पर एयरोप्लेन फ़ैक्ट्री की फ़ोटो शेयर की है.