はじめに
MicroPythonのBluetooth通信について気になったのでまとめてみます
Bluetoothとは
Bluetoothは近距離 無線通信規格の一つです
Bluetoothの利点
- 省電力
- アップグレードが容易
- 赤外線通信よりも広範囲
- 音声とデータの転送ができる
- 使用できるデバイスが安価
Bluetoothの欠点
- Wi-Fiに比べて帯域幅が狭い
- デバイス間の短距離通信のみ可能
- 屋内環境において電波の減衰が起こる
BLE(Bluetooth Low Energy)とは
Bluetoothの一部で,バージョン4.0から追加された低消費電力の通信規格です.電池寿命の延長を目的として,無線部分の消費電力削減がされています.このおかげでボタン電池で複数年稼働するため,IoTデバイスの通信方式で注目されています.
MicroPythonのBluetooth
Bluetoothモジュールはボード上のBluetoothコントローラーへのインターフェースを提供していて,Bluetooth Low Energy(BLE)をサポートしています.セントラル(Central),ペリフェラル(Peripheral),ブロードキャスター(Broadcaster),オブザーバー(Observer)のロールがあり,GATTサーバ/クライアントロール,L2CAP connection-oriented-channelsもあります.
クラスBLE
コンストラクタ
class bluetooth.BLE
- BLEオブジェクトを返す
設定
BLE.active( [active,] /)
- オプションでBLE無線のアクティブ状態を変更し,現在の状態を返す
BLE.config('param'./)
BLE.config(*,param=value,...)
- BLEインターフェイスの設定値を取得or設定
- パラメーター名を文字列として一度に1つだけ指定する
- 値を設定する場合には,キーワード構文を使って,一度に1つ以上のパラメーターを設定できる
使える値 | 'addr_mode' |
'mac' |
'gap_name' |
---|---|---|---|
出来る事 | アドレスモードを設定 | 現在利用中のアドレスを取得 | サービス0x1800,キャラクタリスティック0x2a00で利用するGAPデバイス名を取得/設定 |
戻り値 | (addr_type, addr) |
ブロードキャスターロール(アドバタイザー):送信側
BLE.gap_advertise(interval_us,adv_data=None,*,resp_data=None,connectable=True)
- 指定された間隔(マイクロ秒単位)でアドバタイジング(Advertising)を開始する
- アドバタイジングを停止するには
interval_us
をNoneに設定する -
adv_data
,resp_data
はバッファプロトコルを実装する任意のタイプにできる(bytes
,bytearray
,str
) -
adv_data
はすべてのブロードキャストに含まれ,resp_data
はアクティブスキャンへの返信として送信される
オブザーバ―ロール(スキャナー):受信側
BLE.gap_scan(duration_ms,interval_us=1280000,window_us=11250,active=False,/
)
-
指定された期間(ミリ 秒単位)持続するスキャン操作を実行する
-
時間していないしでスキャンするときは
duration_ms
を0に設定する -
スキャンを停止するに
duration_ms
をNoneに設定する -
スキャン結果毎に
_IRQ_SCAN_RESULT
イベントが発生する,イベントデータは(addr_type, addr, adv_type, rssi, adv_data)
-
addr_type
の値はPUBLICまたはRANDOMアドレスであるかを示す- 0x00 - PUBLIC
- 0x01 - RANDOM(RANDOM,RPA,NRPAのいずれかで,どれであるかはアドレス自体にエンコードされている)
-
'adv_type'
の値は次のBluetooth仕様に対応している- 0x00 - ADV_IND - 接続/スキャン可能な無向アドバタイジング
- 0x01 - ADV_DIRECT_IND - 接続可能な有向アドバタイジング
- 0x02 - ADV_SCAN_IND - スキャン可能な無向アドバタイジング
- 0x03 - ADV_NONCONN_IND - 接続不可能な無向アドバタイジング
- 0x04 - SCAN_RSP - スキャン応答
-
スキャンの応答を結果として受け取りたい場合は,
active
をTrueにする
セントラルロール
セントラルデバイスは,オブザーバーロールを使うか,既知のアドレスで検出したペリフェラルに接続できる
BLE.gap_connect(addr_type,addr,scan_duration_ms=2000,min_conn_interval_us=None,max_conn_interval_us=None,/)
- ペリフェラルに接続する
- 未処理の接続試行を早期にキャンセルするには
gap_connect(None)
を呼び出す - 接続に成功すると
_IRQ_PERIPHERAL_CONNECT
イベントが発生する.接続の試行をキャンセルすると_IRQ_PERIPHERAL_DISCONNECT
イベントが発生する - デバイスからのアドバタイジングペイロードを受信するまでscan_duration_msまで待機する
- 接続間隔はmin_conn_interval_usおよびmax_conn_interval_usのいずれかまたは両方を使ってマイクロ秒単位で設定できる.それ以外の場合は,通常30000~50000マイクロ秒の間でデフォルトの間隔が選択される.間隔を短くするとスループットが向上するが消費電力は増加する
ペリフェラルロール
ペリフェラルデバイスは,接続可能なアドバタイズを送信することできる.通常はgatts_register_serveces
を用いて最初に登録されたサービスとキャラクタリスティックを持つGATTサーバとして動作する.
セントラルが接続すると`_IRQ_CENTRAL_CONNECT'イベントが発生する
セントラル&ペリフェラルロール
BLE.gap_disconnect(conn_handle,/)
- 指定した接続ハンドル(接続の識別)を切断する
- (ペリフェラルとして動作している)このデバイスに接続したセントラル,または(セントラルとして動作している)このデバイスに以前に接続されていたペリフェラルのいずれかになる
- 切断に成功すると
_IRQ_PERIPHERAL_DISCONNECT
または_IRQ_CENTRAL_DISCONNECT
イベントが発生する - 接続ハンドルが接続されていない場合は
False
を,そうでない場合はTrue
を返す
GATTサーバ
- GATTサーバには登録されたサービスのセットがある
- 各サービスにはキャラクタリスティックが含まれていることがあり,各キャラクタリスティックは値を持つ
- キャラクタリスティックには,それ自体に値を持つディスクリプタを含めることもできる
- 値はローカルに保存され,サービス登録中に精製される「値ハンドル(value handle)」によってアクセスされる.また,リモートのクライアントデバイスから読み書きすることもできる.さらに,ペリフェラルは接続ハンドルを介して接続されたクライアントにキャラクタリスティックを「通知」できる.
- セントラルまたはペリフェラルのいずれかのロールを持つデバイスがGATTサーバとして機能するが,ペリフェラルがサーバとして機能するのが一般的
- キャラクタリスティックとディスクリプタのデフォルト最大サイズは20バイト
キャラクタリスティックとは
- ペリフェラル機器がセントラル機器に公開して共有するデータ構造
- ペリフェラル機器とセントラル機器はこのキャラクタリスティックを介してデータのやり取りを行う
BLE.gatts_register_services(services_definition,/)
- 指定したサービスでサーバを構成し,既存サービスを置換する
- services_definitionはサービスのリストであり,各サービスはUUIDとキャラクタリスティックのリストを含む2項目のタプル
- 各キャラクタリスティックは,UUID,フラグ値,およびオプションのディスクリプタのリストを含む2または3項目のタプル
- 各ディスクリプタはUUIDとフラグ値を含む2項目のタプル
BLE.gatts_read(value_handle,/)
- このハンドルのためのローカル値(
gatts_write
かリモートクライアントで書き込まれたもの)を読み取る
BLE.gatts_write(value_handle,data,send_update=False,/)
- このハンドルのローカル値を書き込む.クライアントによって読み取ることができる
- send_updateが
True
の場合,サブスクライブしているクライアントにこの書き込みいついて通知される
BLE.gatts_indicate(conn_handle,value_handle,/)
- キャラクタリスティックの現在の値を含む指示(indication)要求を接続中のクライアントに送信する
- acknowledgment(あるいはタイムアウトなどの失敗)があった場合,
_IRQ_GATTS_INDICATE_DONE
イベントが発生する
BLE.gatts_set_buffer(value_handle,len,append=False,/)
- 値の内部バッファサイズをバイト数で設定.受信可能な最大の書き込みが制限される.デフォルトは20
- appendを
True
に設定すると,すべてのリモート書き込みが現在の値に置き換えられるのではなく,追加される -
gatts_read
を使用すると,読み取り後に値がクリアされる.
GATTクライアント
GATTクライアントは,リモートのGATTサーバ上のキャラクタリスティックを発見し,読み書きできる
セントラルロールを持つデバイスがGATTクライアントとして動作するのが一般的ですが,接続したセントラルについての情報を発見するためにペリフェラルがクライアントとして動作することも可能
BLE.gattc_discover_servives(conn_handle,uuid=None,/)
- サービスについて接続されたサーバを問い合わせる
- オプションで照会するサービスのUUIDを指定できる
- 検出された各サービスについて
_IRQ_GATTC_SERVICE_RESULT
イベントが発生し,検索が完了すると_IRQ_GATTC_SERVICE_DONE
になる
BLE.gattc_discover_characteristics(conn_handle,start_handle,end_handle,uuid=None,/)
- 指定した範囲のキャラクタリスティックについて接続されたサーバを問い合わせる
- オプションで照会するキャラクタリスティックのUUIDを指定できる
- 任意のサービスのキャラクタリスティックを検索するには
start_handle_=1
,end_handle=0xffff
とする - 検出された各キャラクタリスティックについて
_IRQ_GATTC_CHARACTERISTIC_RESULT
イベントが発生し,検索が完了すると_IRQ_GATTC_CHARCTERISIC_DONE
になる
BLE.gattc_discover_descriptors(conn_handle,start_handle,end_handle,/)
- 指定した範囲のディスクリプタについて接続されたサーバを問い合わせる
- 検出された各ディスクリプタについて
_IRQ_GATTC_DESCRIPTOR_RESULT
イベントが発生し,検索が完了すると_IRQ_GATTC_DESCRIPTOR_DONE
になる
BLE.gattc_write(conn_handle,value_handle,data,mode=0,/)
- 指定したキャラクタリスティックあるいはディスクリプタについて接続されたサーバにリモート書き込みを発行する
- 引数
mode
は書き込み動作を指定する.現在サポートされているのは以下-
mode=0
(デフォルト)は応答なしの書き込み.書き込みはリモートサーバに送信されるが,確認は返されず,イベントは発生しない -
mode=1
は応答付きの書き込み.リモートサーバはデータを受信したという応答/承認を送信するように要求される
-
BLE.gattc_exchange_mtu(conn_handle,/)
-
BLE.config(mtu=value)
で設定した優先MTUを使って,接続されているサーバとのMTU交換を開始する - MTU交換が完了すると
_IRQ_MTU_EXCHANGED
イベント発生する
L2CAP connection-oriented-channels
2つのBLEデバイス間でのソケットのようなデータ交換が可能になる.デバイスがGAPを介して接続されると,どちらかのデバイスは他方のデバイスがPSM(Protoclo/Service Multiplexer)番号でリスンできる.
アクティブなL2CAPチャネルは,確率された接続ハンドルとCID(チャネルID)によって識別される.
BLE.l2cap_listen(psm,mtu,/)
- 指定の
psm
とmtu
に指定のローカルMTUで,L2CAPチャネル要求の着信のためのリスンを開始する - リモートデバイスが接続を開始すると
_IRQ_L2CAP_ACCEPT
イベントが発生し,リスン中のサーバに着信接続を(0以外の整数を返すことで)拒否する機会が与えられる - 接続が受け入れられると
_IRQ_L2CAP_CONNECT
イベントが発生し,サーバがチャネルID(CID)とローカルおよびリモートのMTUを取得できるようになる
BLE.l2cap_connect(conn_handle,psm,mtu,/)
-
mtu
に設定したローカルMTUで,指定したpsm
上のリスニングピアに接続する - 接続に成功すると
_IRQ_L2CAP_CONNECT
イベントが発生し,クライアントはCID - CIDとローカルおよびリモートの(ピア)MTUを取得できるようになる
- 接続に失敗すると
_IRQ_L2CAP_DISCONNECT
イベントが発生し,ステータスは0以外になる
BLE.l2cap_disconnect(conn_handle,cid,/)
- 指定した
conn_handle
とcid
を持つアクティブなL2CAPチャネルを切断する
BLE.l2cap_send(conn_handle,cid,buf,/)
-
conn_handle
とcid
で識別されるL2CAPチャネル上で,指定したbuf
(バッファプロトコルをサポートしている必要アリ)を送信する - 指定されたバッファは,リモート(ピア)MTUよりも大きく,ローカルMTUの2倍以下のサイズにすることはできない
- これはチャネルがストールしている場合に,
False
を返す.この状態では_IRQ_L2CAP_SEND_READY
イベントを受信するまで(リモートデバイスがより多くのクレジットを付与したとき,通常はデータ受信して処理した後に発生する),l2cap_send
を再度呼び出してはならない
BLE.l2cap_recvinto(conn_handle,cid,buf,/)
- 指定した
conn_handle
およびcid
から,指定したbuf
にデータを受信する - チャネルから読み込んだバイト数を返す
-
buf
がNoneの場合,利用可能なバイト数を返す
まとめ
MicropythonでBluetoothやろうとするといろいろできそうです.Bluetooth通信に関する用語が全然わかりませんでしたが,少しだけ理解することが出来ました.
参考にしたサイト