micro:bitとブラウザ間で文字列をやり取りするまでの手順

# 目的

スマホ等からWebBluetoothを使って micro:bit に文字列を送信、
また、逆に micro:bit からスマホ等に文字列を送信するための手順をまとめています。

----

# 使用するもの

- micro:bit
- USB ケーブル
- WebBluetooth 対応ブラウザ（2020年1月時点でPCまたはAndroidのChrome）
- テキストエディタ

----

# micro:bit 側のプログラム作成

----

## まずは Bluetooth に接続、切断されたことがわかるようにしてみます。

----

https://makecode.microbit.org にアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/92c60dfb-4e9d-53d6-4180-5da97288f3dd.png)

----

新しいプロジェクトを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/2c0c5799-34e7-a076-6c3e-6f301a0e6efb.png)

----

右上の歯車をクリックし、プロジェクトの設定を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/390376ed-9384-5f68-f911-74f0e1d26b9c.png)
※日本語表示になっていない場合は、Language から、日本語を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/023cd40f-f522-5ef6-997b-9b7075894fdc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/55fd0f66-1ebd-a6da-3faf-1f4a5d483158.png)

----

名前を UART にし、No Pairing Required: Anyone can connect via Bluetooth. を有効にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/5e04a0eb-9c12-825c-7158-dccebc0d05f2.png)
※これで WebBluetoothから面倒な手続きなしで micro:bit に接続できるようになります。

----

ブロックプログラミングを始めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/e401157b-7b92-d3dc-5ba9-bfeb8a048292.png)

----

高度なブロックを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/579d38c1-54f3-9b69-c546-c9eb32a4ac19.png)

----

拡張機能を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/ee6d593f-9c04-45ac-86d5-c18e65318e77.png)

----

bluetooth を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/f62831f3-03c5-290d-d0b8-2c5725753032.png)

----

「一部の拡張機能を削除してbluetoothを追加する」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/7f82dfcd-4e43-89b6-d984-80820a5dbce8.png)

----

bluetooth - その他 のなかの「Bluetooth UARTサービス」を「最初だけ」ブロックの中に配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/efcc31a7-96fc-6716-c3de-f042b4fccf6b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/77e72356-1048-4c23-3542-e3657b6970c8.png)

----

接続されていない状態がわかるように、基本 - アイコン から目を閉じた顔マークを配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/960a6e93-517c-e39b-0a20-fdcffbb0f07a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/6b2355d5-0cc9-8a1d-a7f9-a70ccaf624c6.png)

----

Bluetooth が接続されたことがわかるように、Bluetooth のなかの 「Bluetooth 接続されたとき」と笑った顔マークを配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/6a53b8d2-10f8-56fb-3a83-8304ef0f1ddd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/54bd31b0-55e6-65a7-56df-3a3c56a06845.png)

----

Bluetooth が切断されたことがわかるように、「Bluetooth 接続が切断されたとき」と目を閉じた顔マークを配置します。（顔マークは先に配置したものを右クリックで複製すると早いです。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/1141c65d-6556-4d0a-eb94-30867e918003.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/ed6a50da-b302-77df-5f9a-c203bee3613f.png)

----

# 作成したプログラムの書き込み

----

右上歯車ボタンを押し、「デバイスを接続する」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/1433815c-198a-2fc4-63e3-6819f4e5c0a5.png)

----

さらに、「デバイスを接続する」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/70216b88-c5a8-642b-df31-ff5f5de00dc6.png)

----

次のようなポップアップが表示されるので、 micro:bit を選択して、「接続」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/1560ed70-f26b-d1ce-5f63-85cc428748be.png)
※これで、画面左下の「ダウンロード」ボタンを押すと、作成したプログラムが直接 micro:bit に書き込まれるようになります。

----
画面左下の「ダウンロード」ボタンを押し、プログラムを書き込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/1c7f0f4c-47cf-24a7-ed65-8b51cac86c07.png)
書き込みが成功すれば microbit に顔マークが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/0ed974da-4d01-5826-ce95-a770ebaa1717.png)


# ブラウザ側のプログラム作成

----

テキストエディタを起動して、次の内容を入力します。

```html
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Micro:bit UART 通信</title>
<style type="text/css">
* {
    font-size: 3vmin;
    padding: 3vmin;
}
body {
    text-align: center;
}
</style>
<h1>Micro:bit UART 通信</h1>
<form>
  <button type="button" id="connect">接続</button>
</form>

<script>
const UUID_UART_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'

let gatt = null

const update = connected => {
    document.getElementById('connect').textContent = connected ? '切断' : '接続'
}

document.getElementById('connect').addEventListener('click', e => {
    if(!(navigator.bluetooth && navigator.bluetooth.requestDevice)) {
        alert('WebBluetooth に未対応のブラウザです。')
        return
    }
    if (document.getElementById('connect').textContent == '接続') {
        navigator.bluetooth.requestDevice({
            filters: [
                { services: [UUID_UART_SERVICE] },
                { namePrefix: 'BBC micro:bit' }
            ]
        }).then(device => {
            gatt = device.gatt
            return gatt.connect()
        }).then(server => {
            update(true)
        }).catch(function(err) {
            alert(err)
        })
    } else {
        gatt.disconnect()
        update(false)
    }
})
</script>
```

----

navigator.bluetooth.requestDevice で micro:bit を探します。
device.gatt が通信用のハンドルのようなものです。
gatt.connect で接続します。
接続が成功したら、ボタンを切断に変えるようにしています。
切断するのは gatt.disconnect です。

----

## Bluetooth 接続の動作確認

----

作成したファイルを uart1.html という名前で保存し、ブラウザで開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/6513a611-a442-f0df-a3f7-5f03241cfeb6.png)

----

「接続」ボタンを押すと、次のようなポップアップが表示されるので、 micro:bit を選択して、「ペア設定」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/62af2d9f-1373-a4b5-54d3-b598161e8bc0.png)

----

うまく行けば、micro:bit の顔の表示が変わり、ブラウザのボタンは切断ボタンに変わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/44686feb-8b12-aa72-78e5-dc3f36bc28c1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/32bee452-74df-0f4f-2c6c-4dabb64ac801.png)

----

切断ボタンを押すと、顔の表示が戻ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/0ed974da-4d01-5826-ce95-a770ebaa1717.png)

----

# micro:bit からブラウザへ文字を送信する

----

## ブラウザ側のプログラム変更

----

下記内容で uart2.html ファイルを作成し、ブラウザで開きます。

```html
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Micro:bit UART 通信</title>
<style type="text/css">
* {
    font-size: 3vmin;
    padding: 3vmin;
}
body {
    text-align: center;
}
textarea {
    vertical-align: middle;
}
</style>
<h1>Micro:bit UART 通信</h1>
<form>
    <div>
        <button type="button" id="connect">接続</button>
        受信内容<textarea id="recieve_text"></textarea>
    </div>
</form>

<script>
const UUID_UART_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'
const UUID_TX_CHAR_CHARACTERISTIC = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'

let gatt = null
let tx = null

const update = connected => {
    document.getElementById('connect').textContent = connected ? '切断' : '接続'
}

document.getElementById('connect').addEventListener('click', e => {
    if(!(navigator.bluetooth && navigator.bluetooth.requestDevice)) {
        alert('WebBluetooth に未対応のブラウザです。')
        return
    }
    if (document.getElementById('connect').textContent == '接続') {
        navigator.bluetooth.requestDevice({
            filters: [
                { services: [UUID_UART_SERVICE] },
                { namePrefix: 'BBC micro:bit' }
            ]
        }).then(device => {
            gatt = device.gatt
            return gatt.connect()
        }).then(server =>
            server.getPrimaryService(UUID_UART_SERVICE)
        ).then(service =>
            service.getCharacteristic(UUID_TX_CHAR_CHARACTERISTIC)
        ).then(characteristic => {
            tx = characteristic
            tx.startNotifications()
            tx.addEventListener('characteristicvaluechanged', e => {
                const text = new TextDecoder().decode(e.target.value)
                document.getElementById('recieve_text').value = text + document.getElementById('recieve_text').value
            })
            update(true)
        }).catch(function(err) {
            alert(err)
        })
    } else {
        gatt.disconnect()
        update(false)
    }
})
</script>
```

----

※uart1.html から変更された部分は次のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/2eea26c2-a8a6-4c6a-bca4-972f837aa54e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/c603c05a-474a-346d-6036-0c465eab7b3d.png)

----

uart1から増えた処理は、gatt を取得したあとに、 
server.getPrimaryService(UUID_UART_SERVICE) で micro:bit の UART 機能にアクセスし、
service.getCharacteristic(UUID_TX_CHAR_CHARACTERISTIC) で micro:bit の送信機能のハンドルを取得しています。
そして、tx.addEventListener で micro:bit が送信したデータを受け取る処理を登録し、
tx.startNotifications で受信を開始しています。

----

## microbit側のプログラム変更

----

「ボタンが押されたとき」のブロックを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/ba469563-eb68-8f18-fe23-fe9308ea206a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/ce4324a8-480f-a6bb-3cfd-823aa8c0d027.png)

----

「Bluetooth UART 文字列を書き出す」を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/20e40a7d-2b2a-37ea-a664-143179a09d3c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/fc0f833a-7e10-75d7-1cc0-61c4729fb6bf.png)

----

書き出す内容を、 Button A pressed. とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/e3f5670a-1698-19e2-a791-0da64f4d97aa.png)

----

左下「ダウンロードボタン」を押して、micro:bit に変更したプログラムを書き込みます。

----

## micro:bit → ブラウザ 文字送信動作確認

----

ブラウザで uart2.html を開きます。

----

接続ボタンを押します。

----

micro:bit の A ボタンを押します。

----

ブラウザの受信内容に、 Button A pressed. と表示されれば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/2af037f7-f3ab-9d66-6282-dc6c653ee2e5.png)

----

# ブラウザから micro:bit へ文字を送信する

## microbit側のプログラム変更

----

「Bluetooth データを受信したとき」のブロックを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/245ce4e4-9e2e-5b41-d59d-30cb60154242.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/f83e075d-db25-21d0-4678-e62126daa5d9.png)

----

「文字列を表示」ブロックを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/8254f2e8-8180-d15e-6565-b0917d4b05f2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/239a5811-c5f5-a83c-3fe1-f7def9880684.png)

----

表示内容を、「Bluetooth UART つぎのいずれかの文字の手前まで読み取る」にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/34142c17-f229-66cd-7993-83a358efc2bd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/65d50117-77a2-afab-96cd-7db34909e0df.png)

----

## ブラウザ側のプログラム変更

----

次の内容で、uart3.html を作成します。

```html
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Micro:bit UART 通信</title>
<style type="text/css">
* {
    font-size: 3vmin;
    padding: 3vmin;
}
body {
    text-align: center;
}
textarea {
    vertical-align: middle;
}
</style>
<h1>Micro:bit UART 通信</h1>
<form>
    <div>
        <button type="button" id="connect">接続</button>
        受信内容<textarea id="recieve_text"></textarea>
    </div>
    <div>
        送信内容
        <input type="text" id="send_text" value="test">
        <button type="button" id="send" disabled>送信</button>
    </div>
</form>

<script>
const UUID_UART_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'
const UUID_TX_CHAR_CHARACTERISTIC = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'
const UUID_RX_CHAR_CHARACTERISTIC = '6e400003-b5a3-f393-e0a9-e50e24dcca9e'

let gatt = null
let tx = null
let rx = null

const update = connected => {
    document.getElementById('connect').textContent = connected ? '切断' : '接続'
    document.getElementById('send').disabled = !connected
}
const send = text => rx.writeValue(new TextEncoder().encode(text + '\n'))

document.getElementById('connect').addEventListener('click', e => {
    if(!(navigator.bluetooth && navigator.bluetooth.requestDevice)) {
        alert('WebBluetooth に未対応のブラウザです。')
        return
    }
    if (document.getElementById('connect').textContent == '接続') {
        navigator.bluetooth.requestDevice({
            filters: [
                { services: [UUID_UART_SERVICE] },
                { namePrefix: 'BBC micro:bit' }
            ]
        }).then(device => {
            gatt = device.gatt
            return gatt.connect()
        }).then(server =>
            server.getPrimaryService(UUID_UART_SERVICE)
        ).then(service =>
            Promise.all([
            service.getCharacteristic(UUID_TX_CHAR_CHARACTERISTIC),
            service.getCharacteristic(UUID_RX_CHAR_CHARACTERISTIC)])
        ).then(characteristics => {
            tx = characteristics[0]
            tx.startNotifications()
            tx.addEventListener('characteristicvaluechanged', e => {
                const text = new TextDecoder().decode(e.target.value)
                document.getElementById('recieve_text').value = text + document.getElementById('recieve_text').value
            })
            rx = characteristics[1]
            update(true)
        }).catch(function(err) {
            alert(err)
        })
    } else {
        gatt.disconnect()
        update(false)
    }
})
document.getElementById('send').addEventListener('click', e => {
    send(document.getElementById('send_text').value)
})
</script>
```

----

※ uart2.html からの変更箇所は次のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/d2039627-f70f-5c7d-53a7-39fbce046bae.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/86bd193c-63d3-7ef4-9380-651d61efb653.png)

----

service.getCharacteristic(UUID_RX_CHAR_CHARACTERISTIC) で micro:bit の受信機能のハンドルを取得し、
rx.writeValue でブラウザから文字列を送信しています。

----

## ブラウザ → micro:bit 文字送信動作確認

----

ブラウザで uart3.html を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/81b8d670-edf0-61c3-29d5-b8f098474038.png)

----

接続ボタンを押して接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/9908bc6b-1f7d-7565-340a-54b87c25c0ee.png)
※接続が成功すれば、送信ボタンが押せるようになります。

----

送信ボタンを押します。成功すると、micro:bit に test という文字がスクロールで表示されます。
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/18fcff00-f182-b33d-0cc8-37a5ad1b4c52.gif)

----

以上で、ブラウザと micro:bit 間の文字列送信ができるようになりました。

これをベースに、ブラウザからコマンドを送って、micro:bit にそのコマンドを判別していろいろな動作をさせたり、
micro:bit からセンサーデータをブラウザに送ってブラウザ側でグラフにしたりすることができそうです。

----

# おまけ

----

計測開始を押すと、micro:bitの光センサーの値が、1秒毎にブラウザに送られてくるプログラムを作ったので共有します。

ブラウザ側
https://programpark.jp/microbit_uart.html

micro:bit側
https://makecode.microbit.org/_gJP7Ab3K7hH9

----

# おわりに

日本語は送受信できませんでした。
1度の送信は20文字までのようです。