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

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

François Beaufort
François Beaufort

Web Serial API क्या है?

सीरियल पोर्ट, एक ऐसा इंटरफ़ेस है जो डेटा को एक से ज़्यादा डिवाइसों के बीच भेजने और पाने की सुविधा देता है.

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

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

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

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

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

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

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

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

एयरप्लेन फ़ैक्ट्री की फ़ोटो
World War II Castle Bromwich Aeroplane Factory

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

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

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

Google Developer कोडलैब में, 5x5 एलईडी मैट्रिक्स पर इमेज दिखाने के लिए, आपको वेब सीरियल एपीआई का इस्तेमाल करना होगा. इससे BBC माइक्रो:बिट बोर्ड का इस्तेमाल करके, उसके साथ इंटरैक्ट किया जा सकता है.

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

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

Polyfill

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

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

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

सुरक्षा से जुड़े समझौते को समझने के लिए, Web Serial API के बारे में जानकारी देने वाले पेज पर मौजूद सुरक्षा और निजता सेक्शन देखें.

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

Chrome टीम को Web Serial API के इस्तेमाल के बारे में आपके विचार और अनुभव जानने में खुशी होगी.

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

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

Web Serial API के GitHub रिपॉज़िटरी पर, खास जानकारी से जुड़ी समस्या दर्ज करें या किसी मौजूदा समस्या में अपने सुझाव/राय जोड़ें.

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

क्या आपको Chrome में इस सुविधा को लागू करने में कोई गड़बड़ी मिली? या क्या इसे लागू करने का तरीका, स्पेसिफ़िकेशन से अलग है?

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

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

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

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

मददगार लिंक

डेमो

धन्यवाद

इस लेख पर समीक्षाएं लिखने के लिए, रेली ग्रांट और जो मेडली का धन्यवाद. Unsplash पर, Birmingham Museums Trust की ओर से ली गई, हवाई जहाज़ फ़ैक्ट्री की फ़ोटो.