前回、Raspberry Piから有線(GPIO)でmicro:bitのLEDドットマトリックス制御をやってみました。↓
今回はBleでmicro:bitを制御してみましたので、備忘録として記しておきます。
本当はBluetooth UARTで通信したかったのですが、少々躓いてしまったので、先ずは手軽に出来そうなBleの「UUIDとHandle」を利用した制御からやってみました。
※Raspberry pi とmicro:bitはbluetoothでペアリング出来る事前提で進めます。Raspberry Piはbluepyモジュールを使うので、インストールしていなければインストールが必要です。
なお、今回の接続方法に関しましては下記サイトを参考にさせていただきました。↓
Raspberry Pi で bluepy を使ってmicro:bitをコントロール
目次
初めに
Bleについて
Ble(ブルートゥース・ロー・エナジー)は省電力のbluetoothの規格で、大きなサイズのデータのやり取りはできませんが、電池持ちが良くなる事からIOT等の様々なセンサーの値のやり取り等に使われているようです。
データのやり取りをする構成は、大きく分けて親機となる「セントラル」と子機となる「ペリフェラル」に分かれます。
おおおまかな接続の流れとしては、先ずペリフェラルがアドバタイズ(Ble接続待ち)を周囲に知らせる為に、接続待機状態であることを無線信号でブロードキャストします。続いて無線信号が届く範囲にセントラルのデバイスが存在し、かつ接続を許可されている状態であれば、そこで接続が完了します。
接続後は、基本的にはペリフェラルからセントラルへの一方通行のやり取り(値などの受け渡し)が一般的なようです。(双方向も可能)
今回、セントラルにはRaspberry Piを、ペリフェラルにはmicro:bitを使用しました。プログラムはpython(micro:bitはmake code)で作成しました。
UUIDとHandleについて
UUID
どちらとも知らなかったのですが、UUIDは「デバイスが提供するサービスの識別ID」のようなもののようです。
micro:bitは「LEDの点灯」や「加速度センサー」等、複数の機能を備えていますが、それらの機能がこのUUIDと結びついている感じです。
少しややこしいですが、簡単に言えばmicro:bit側でLED点灯の処理をプログラムしなくても、セントラル側でLED関連のUUIDを使用すれば、セントラル側でmicro:bitのLEDを点灯させる処理が可能になるという事です。
以下にUUIDが一覧できるサイトのURLを貼っておきます。↓
Handle
BleのペアリングにはペリフェラルのMACアドレス(micro:bit)が分かれば接続できますが、それだけではUUIDを利用して、セントラルからペリフェラルの制御が出来ないようです。
そこで必要なのが「Handle」になります。これは、デバイスを識別するソフトウェア上で一意に決められたIDのようです。
つまり、BLEコネクション確立後、ペリフェラルのHandleが分かっていれば、UUIDで任意の制御が可能になります。
UUIDでの制御はHandleが必ず必要ってことですね。
ペリフェラルのMACアドレス、UUID、Handleの調べ方
MACアドレス
ペリフェラルをアドバタイズ状態にして、Raspberry Piの「Bluetoothctl」コマンドでbluetoothを有効にし、「scan on」で接続可能なデバイスを検索します。
xx:xx:xx:xx:xx:xx:microbit のような表示が出るので、これがMACアドレスになります。後にプログラムに埋め込むので、控えておきます。
なお、micro:bitは アドバタイズ状態にしておくだけでいいので、 make codeで「Blutooth 接続されたとき」のみ入れておけばOKです。※今回はLEDのUUIDを使用するので、Bluetooth LEDサービスも入れています。
UUID,Handle
ペリフェラルをアドバタイズ状態にして 、下記プログラムをセントラル側(ラズパイ)で実行します。
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 |
import sys import bluepy def main(): try: peri = bluepy.btle.Peripheral() peri.connect("DB:5A:9B:16:E9:A6", bluepy.btle.ADDR_TYPE_RANDOM) # addrTypeがpublic なら、ADDR_TYPE_PUBLICを指定 except: print("device connect error") sys.exit() charas = peri.getCharacteristics() for chara in charas: print("======================================================") print(" UUID : %s" % chara.uuid ) print(" Handle %04x: %s" % (chara.getHandle(), chara.propertiesToString())) peri.disconnect() if __name__ == "__main__": if len(sys.argv) == 1: print('Usage: getHandle.py BLE_DEVICE_ADDRESS') sys.exit() devadr = sys.argv[1] main() |
なお、プログラム実行の際には、ファイル名の後にペリフェラルのMACアドレスの入力が必要です。
プログラムをscan.pyとすれば、
python3 scan.py xx:xx:xx:xx:xx:xx
で実行します。
実行後、下図のような利用出来るUUID一覧が表示されます。
ここでの注意点としては、ペリフェラルのmicro:bit側でBluetooth LEDのサービスを利用出来る状態(先ほどのmake codeの画面の先頭のブロック)にしておかないと、目的のUUIDが表示されないことです。
UUIDが表示されたら、後ほどのプログラムで利用するので、UUIDとHandleを控えておきます。
今回、目的のLEDに関するUUIDは「e95d93ee-251d-470a-a062-fa1922dfa9a8」になりますので、付随するHandle「0x0029」も控えておきます。
メインプログラムの作成
python CGI
それでは、最後にRaspberry piのメインプログラムを作成します。
今回、ラズパイに立てたWEBサーバーを通して、ブラウザからmicro:bitを制御したいので、冒頭に張ったリンクの前回作成したプログラムを応用します。
前回作成したpyrhon CGIファイルを以下に変更します。
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 |
#!/usr/bin/python3 # -*- coding: utf-8 -*- import cgi import time import bluepy HANDLE_LED = 0x0029 devadr = "DB:5A:9B:16:E9:A6" peri = bluepy.btle.Peripheral() peri.connect(devadr, bluepy.btle.ADDR_TYPE_RANDOM) form = cgi.FieldStorage() recieve = form.getvalue('name') if recieve == 'hhhhh': peri.writeCharacteristic(HANDLE_LED, b'AAAAA' ) peri.disconnect() print('Content-type: text/html\n') print(recieve) elif recieve == "kkkk": peri.writeCharacteristic(HANDLE_LED, b'BBBBB' ) peri.disconnect() print('Content-type: text/html\n') print(recieve) elif recieve == "jjjj": peri.writeCharacteristic(HANDLE_LED, b'CCCCC' ) peri.disconnect() print('Content-type: text/html\n') print(recieve) elif recieve == "ssss": print('Content-type: text/html\n') print(recieve) |
押したボタンによってAAAA~CCCCの文字をスクロールさせるようmicro:bitを制御しています。
CGIスクリプトなので、このページを呼び出すたびに接続、切断を繰り返している(ボタンを押すたびに発生)ので遅延が大きいですが、一応正常に動作します。
完成
こんな感じになります。↓
read(ペリフェラルからセントラルへのデータ転送)も可能みたいですので、いつかやってみようと思います。
あと、bluetooth UARTもやってみたい。難しいんだけど。。