要するに、WebシリアルAPIを使用すると、ウェブ上で純粋なJavaScriptを使用して双方向のシリアル通信を実現できます。もちろん、組み込みシステムの開発等にも使用できます。
詳細な使用法は公式ドキュメントを参照してください。この記事では基本的な使用法のみを紹介します。
環境要件
デスクトップ向けのChromiumのバージョン89以上が必要です。
最新版のChromeやEdge等を使用できます。IEやFirefoxはサポートされていません。
以下のコードを使用して、ブラウザがWebシリアルAPIをサポートしているかどうかをテストできます。
1
2
3
|
if ('serial' in navigator) {
console.log('WebシリアルAPIをサポートしています');
}
|
コンソールにWebシリアルAPIをサポートしています
と表示されれば、ブラウザはWebシリアルAPIをサポートしています。
WebシリアルAPIの使用に関して、以下の注意事項もあります。
- WebシリアルAPIは設計上非同期型です。
- プロジェクトをオンラインにデプロイする場合、httpsプロトコルを使用する必要があります。ローカル環境ではこの制限はありません。
- 通信はユーザーが明示的にトリガーするイベントにバインドする必要があり、自動的に通信を開始することは許可されていません。
これらを確認したら、次の手順に進みましょう。
シリアル接続の開始
先ず、シリアル権限を取得する必要があります。以下のコードはボタンが押された時にユーザープロンプトを表示し、ユーザーがシリアルポートを選択するようにします。
1
2
3
|
connectButton.addEventListener('click', async () => {
const port = await navigator.serial.requestPort();
});
|
選択が完了したら、シリアルポートに接続することができます。
1
|
await port.open({ baudRate: 9600 });
|
このメソッドでは、ストップビット、データビット、パリティモード等のオプションも指定できますが、ここでは割愛します。
データの送受信
データの送受信には次のコードを使用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// dataを送信
const writer = port.writable.getWriter();
await writer.write(data);
await writer.close();
// valueを受信し、コンソールに表示
const reader = port.readable.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
console.log(value);
}
|
上記のコードではUint8配列の送受信のみを扱います。文字列の送受信を行いたい場合は、TextEncoder及びTextDecoderを使用することができます。これらは文字列をUTF-8符号化及び復号できます。
1
2
3
4
5
6
7
8
9
|
// 文字列をUint8配列に符号化
const encoder = new TextEncoder();
const data = encoder.encode('Hello, world!');
console.log(data); // Uint8Array(13) [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]
// Uint8配列を文字列に復号
const decoder = new TextDecoder();
const value = decoder.decode(data);
console.log(value); // 'Hello, world!'
|
データの受信順序を確保するために、コードにデバウンスを追加する必要があります。また、通常は数百ミリ秒ごとに受信したデータを一度コンソールに出力する必要があります。
最終的なコード例は以下の通りです。なお、このコードには予期しない状況への対処が一切含まれていませんので、注意してください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
let port; // シリアルポートオブジェクト
let debounceTimeout; // デバウンス遅延タイマー
let delayTime = 500; // 遅延時間
connectButton.addEventListener('click', () => {
// 以前のデバウンス遅延タイマーをクリア
clearTimeout(debounceTimeout);
// 新しいデバウンス遅延タイマーを作成
debounceTimeout = setTimeout(async () => {
// シリアルポートに接続
port = await navigator.serial.requestPort();
await port.open({ baudRate: 9600 });
console.log('Serial port connected');
// シリアルデータを受信
const reader = port.readable.getReader();
const decoder = new TextDecoder();
let receivedData = []; // 受信データを格納するための配列
while (true) {
const { value, done } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
receivedData = receivedData.concat(Array.from(value)); // 受信したバイトを配列に追加
// 受信したデータを一度表示
setTimeout(() => {
const text = decoder.decode(new Uint8Array(receivedData));
console.log(text);
receivedData = []; // 受信したデータをクリア
}, delayTime);
}
}, delayTime);
});
// データを送信
sendButton.addEventListener('click', async () => {
const writer = port.writable.getWriter();
const encoder = new TextEncoder();
const data = encoder.encode('Hello, world!');
await writer.write(data);
await writer.close();
});
|
一歩前進
より複雑な使用法については、ぜひ公式ドキュメントを参照してください。
筆者はWebシリアルAPIを基にして、簡単なWebシリアルデバッグツールを作成しました。より多くのオプションを設定したり、UTF-8以外の符号化方式を使用したり、予期せぬ状況に対処したりする等の場合には、そのコードも参考にできます。