ubluetooth --- 低レベル Bluetooth

このモジュールは、ボード上の Bluetooth コントローラーへのインターフェースを提供します。現在、これは、セントラル、プリフェラル、ブロードキャスター、オブザーバーのロールで Bluetooth Low Energy(BLE)をサポートしており、デバイスは複数のロールで同時に動作できます。

このAPIは、低レベルの Bluetooth プロトコルに相当するもので、特定のデバイスタイプなどの高レベルの抽象化のビルディングブロックを提供します。

注釈

このモジュールはまだ開発中であり、そのクラス、関数、メソッド、定数は変更される可能性があります。

クラス BLE

コンストラクタ

class ubluetooth.BLE

シンゲルトンの BLE オブジェクトを返します。

設定

BLE.active([active])

オプションでBLE無線のアクティブ状態を変更し、現在の状態を返します。

このクラスの他のメソッドを使用する前には、BLE無線をアクティブにする必要があります。

BLE.config('param')
BLE.config(param=value, ...)

BLE インターフェイスの設定値を取得または設定します。値を取得するには、パラメーター名を文字列として一度に1つだけ指定します。値を設定する場合には、キーワード構文を使って、一度に1つ以上のパラメーターを設定できます。

現在サポートされている値は次のとおりです:

  • 'mac': Returns the device MAC address. If a device has a fixed address (e.g. PYBD) then it will be returned. Otherwise (e.g. ESP32) a random address will be generated when the BLE interface is made active.

    注記: ポートによっては、この値にアクセスするのに、(コントローラから MAC アドレスを取得できるように)インタフェースをアクティブにして"おく必要があります

  • 'gap_name': サービス 0x1800、キャラクタリスティック(Characteristic) 0x2a00 で利用する GAP デバイス名を取得/設定します。これはいつでも設定でき、何度も変更できます。

  • 'rxbuf': 着信イベントの保存に使用される内部バッファーのサイズをバイト単位で取得/設定します。このバッファは BLE ドライバー全体に対してグローバルであるため、すべてのキャラクタリスティック(Characteristic)を含むすべてのイベントの着信データを処理します。これを増やすと、バーストな受信データ(スキャン結果など)の処理が改善され、セントラル(Central)なロール(Role)がより大きなキャラクタリスティック値を受信できるようになります。

イベント処理

BLE.irq(handler)

BLE スタックからのイベントのコールバックを登録します。 handler に指定するコールバックは二つの引数 event (後述するイベントコードのいずれか)と data (イベント固有の値のタプル)をとります

注記: タプルの addr, adv_data, char_data, notify_data, uuid 項目は、 ubluetooth モジュールによって管理されるデータへの参照です(つまり、複数のイベントハンドラー呼び出しで同じインスタンスが再利用されます)。プログラムがハンドラの外部でこのデータを使う場合、まず bytes(addr) または bluetooth.UUID(uuid) などを使ってこれらのデータをコピーする必要があります。

すべてのイベントを処理するイベントハンドラーの例を示します:

def bt_irq(event, data):
    if event == _IRQ_CENTRAL_CONNECT:
        # A central has connected to this peripheral.
        conn_handle, addr_type, addr = data
    elif event == _IRQ_CENTRAL_DISCONNECT:
        # A central has disconnected from this peripheral.
        conn_handle, addr_type, addr = data
    elif event == _IRQ_GATTS_WRITE:
        # A central has written to this characteristic or descriptor.
        conn_handle, attr_handle = data
    elif event == _IRQ_GATTS_READ_REQUEST:
        # A central has issued a read. Note: this is a hard IRQ.
        # Return None to deny the read.
        # Note: This event is not supported on ESP32.
        conn_handle, attr_handle = data
    elif event == _IRQ_SCAN_RESULT:
        # A single scan result.
        addr_type, addr, adv_type, rssi, adv_data = data
    elif event == _IRQ_SCAN_DONE:
        # Scan duration finished or manually stopped.
        pass
    elif event == _IRQ_PERIPHERAL_CONNECT:
        # A successful gap_connect().
        conn_handle, addr_type, addr = data
    elif event == _IRQ_PERIPHERAL_DISCONNECT:
        # Connected peripheral has disconnected.
        conn_handle, addr_type, addr = data
    elif event == _IRQ_GATTC_SERVICE_RESULT:
        # Called for each service found by gattc_discover_services().
        conn_handle, start_handle, end_handle, uuid = data
    elif event == _IRQ_GATTC_SERVICE_DONE:
        # Called once service discovery is complete.
        # Note: Status will be zero on success, implementation-specific value otherwise.
        conn_handle, status = data
    elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
        # Called for each characteristic found by gattc_discover_services().
        conn_handle, def_handle, value_handle, properties, uuid = data
    elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
        # Called once service discovery is complete.
        # Note: Status will be zero on success, implementation-specific value otherwise.
        conn_handle, status = data
    elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
        # Called for each descriptor found by gattc_discover_descriptors().
        conn_handle, dsc_handle, uuid = data
    elif event == _IRQ_GATTC_DESCRIPTOR_DONE:
        # Called once service discovery is complete.
        # Note: Status will be zero on success, implementation-specific value otherwise.
        conn_handle, status = data
    elif event == _IRQ_GATTC_READ_RESULT:
        # A gattc_read() has completed.
        conn_handle, value_handle, char_data = data
    elif event == _IRQ_GATTC_READ_DONE:
        # A gattc_read() has completed.
        # Note: The value_handle will be zero on btstack (but present on NimBLE).
        # Note: Status will be zero on success, implementation-specific value otherwise.
        conn_handle, value_handle, status = data
    elif event == _IRQ_GATTC_WRITE_DONE:
        # A gattc_write() has completed.
        # Note: The value_handle will be zero on btstack (but present on NimBLE).
        # Note: Status will be zero on success, implementation-specific value otherwise.
        conn_handle, value_handle, status = data
    elif event == _IRQ_GATTC_NOTIFY:
        # A peripheral has sent a notify request.
        conn_handle, value_handle, notify_data = data
    elif event == _IRQ_GATTC_INDICATE:
        # A peripheral has sent an indicate request.
        conn_handle, value_handle, notify_data = data
    elif event == _IRQ_GATTS_INDICATE_DONE:
        # A central has acknowledged the indication.
        # Note: Status will be zero on successful acknowledgment, implementation-specific value otherwise.
        conn_handle, value_handle, status = data

イベントコードには次のものがあります:

from micropython import const
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)
_IRQ_GATTS_READ_REQUEST = const(4)
_IRQ_SCAN_RESULT = const(5)
_IRQ_SCAN_DONE = const(6)
_IRQ_PERIPHERAL_CONNECT = const(7)
_IRQ_PERIPHERAL_DISCONNECT = const(8)
_IRQ_GATTC_SERVICE_RESULT = const(9)
_IRQ_GATTC_SERVICE_DONE = const(10)
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
_IRQ_GATTC_DESCRIPTOR_RESULT = const(13)
_IRQ_GATTC_DESCRIPTOR_DONE = const(14)
_IRQ_GATTC_READ_RESULT = const(15)
_IRQ_GATTC_READ_DONE = const(16)
_IRQ_GATTC_WRITE_DONE = const(17)
_IRQ_GATTC_NOTIFY = const(18)
_IRQ_GATTC_INDICATE = const(19)
_IRQ_GATTS_INDICATE_DONE = const(20)

ファームウェアのスペースを節約するために、これらの定数は ubluetooth モジュールには含まれていません 。上記のリストから必要なものをプログラムに追加してください。

ブロードキャスターロール(アドバタイザー)

BLE.gap_advertise(interval_us, adv_data=None, resp_data=None, connectable=True)

指定された間隔(マイクロ秒単位)でアドバタイジング(Advertising)を開始します。この間隔は、625us に最も近いところで切り捨てられます。アドバタイジングを停止するには interval_usNone に設定します。

adv_dataresp_data はバッファプロトコルを実装する任意のタイプにできます(bytes, bytearray, str など)。 adv_data はすべてのブロードキャストに含まれ、 resp_data はアクティブスキャンへの返信として送信されます。

注記: adv_data (または resp_data)が None の場合、前の gap_advertise 呼び出しに渡されたデータが再利用されます。これにより gap_advertise(interval_us) だけで、ブロードキャスターはアドバタイジングを再開できます。アドバタイジングペイロードをクリアするには、空の bytes 、すなわち b'' を渡します。

オブザーバーロール(スキャナー)

BLE.gap_scan(duration_ms[, interval_us][, window_us][, active])

指定された期間(ミリ 秒単位)持続するスキャン操作を実行します。

無期限にスキャンするには duration_ms0 に設定します。

スキャンを停止するには duration_msNone に設定します。

オプションでデューティサイクル(duty cycle)を設定するには interval_uswindow_us を使います。スキャナは全体の duration_ms ミリ秒の間の interval_us マイクロ秒毎に window_us マイクロ秒間実行します。 interval_uswindow_us のデフォルト値はそれぞれ 1.28 と 11.25 です(バックグラウンドスキャン)。

スキャン結果ごとに、_IRQ_SCAN_RESULT イベントが発生します。イベントデータは (addr_type, addr, adv_type, rssi, adv_data) です。adv_type の値は次の Bluetooth 仕様に対応しています:

  • 0x00 - ADV_IND - 接続/スキャン可能な無向アドバタイジング
  • 0x01 - ADV_DIRECT_IND - 接続可能な有向アドバタイジング
  • 0x02 - ADV_SCAN_IND - スキャン可能な無向アドバタイジング
  • "0x03 - ADV_NONCONN_IND - 接続不可能な無向アドバタイジング
  • 0x04 - SCAN_RSP - スキャン応答

スキャンの応答を結果として受け取りたい場合は、 activeTrue にします。

スキャンが終了すると(終了時間になったか、明示的に停止した場合)、 _IRQ_SCAN_DONE イベントが発生します。

ペリフェラルロール(GATT サーバー)

BLE ペリフェラルには登録されたサービスのセットがあります。各サービスにはキャラクタリスティック(Characteristic)が含まれていることがあり、各キャラクタリスティックは値を持ちます。キャラクタリスティックには、それ自体に値を持つディスクリプタを含めることもできます。

これらの値はローカルに保存され、サービス登録中に生成される「値ハンドル(value handle)」によってアクセスされます。また、リモートのセントラルデバイスから読み書きすることもできます。さらに、プリフェラルは接続ハンドルを介して接続されたセントラルにキャラクタリスティックを「通知(notify)」できます。

キャラクタリスティックとディスクリプタのデフォルト最大サイズは 20 バイトです。セントラルによってそれらに書き込まれたものはすべて、この長さに切り捨てられます。ただし、セントラルから特定のキャラクタリスティックへのより大きな書き込みを許可したくて、ローカル書き込みの最大サイズを大きくするには、登録後に gatts_write を使います。たとえば gatts_write(char_handle, bytes(100)) のようにします。

BLE.gatts_register_services(services_definition)

指定したサービスでプリフェラルを構成し、既存のサービスを置換します。

services_definitionサービス のリストであり、各 サービス は UUID と キャラクタリスティック のリストを含む2項目のタプルです。

キャラクタリスティック は、UUID、 フラグ 値、およびオプションの ディスクリプタ のリストを含む2または3項目のタプルです。

ディスクリプタ は UUID と フラグ 値を含む2項目のタプルです。

フラグ は、後述する値 ubluetooth.FLAG_READ, ubluetooth.FLAG_WRITE, ubluetooth.FLAG_NOTIFY のビット論理和の組み合わせです。

戻り値は、タプル(各項目は値ハンドル)のリスト(サービスごとに1項目)です。キャラクタリスティックとディスクリプタのハンドルは、定義された順序で同じタプルにフラット化されます。

次の例では、2つのサービス(心拍数と Nordic UART)を登録します。

HR_UUID = bluetooth.UUID(0x180D)
HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
HR_SERVICE = (HR_UUID, (HR_CHAR,),)
UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,)
UART_SERVICE = (UART_UUID, (UART_TX, UART_RX,),)
SERVICES = (HR_SERVICE, UART_SERVICE,)
( (hr,), (tx, rx,), ) = bt.gatts_register_services(SERVICES)

3項目のハンドル (hr, tx, rx) は gatts_read, gatts_write, gatts_notify, gatts_indicate で使えます。

注記: サービスを登録する前に、アドバタイジングを停止する必要があります。

BLE.gatts_read(value_handle)

このハンドルのためのローカル値(gatts_write かリモートセントラルで書き込まれたもの)を読み取ります。

BLE.gatts_write(value_handle, data)

このハンドルのローカル値を書き込みます。これは、セントラルによって読み取ることができます。

BLE.gatts_notify(conn_handle, value_handle[, data])

接続されているセントラルにノーティフィケーション要求を送信します。

data を指定すると、その値が通知の一部としてセントラルに送信されます。ローカル値は変更されません。

data を指定しない場合、現在のローカル値(gatts_write で設定された値)が送信されます。

BLE.gatts_indicate(conn_handle, value_handle)

接続されているセントラルにインディケーション要求を送信します。

注記: このメソッドは現在のところカスタム値の送信をサポートしておらず、常に現在のローカル値(gatts_write で設定したもの)を送信します。

acknowledgment (あるいはタイムアウトなどの失敗)があった場合、 _IRQ_GATTS_INDICATE_DONE イベントが発生します。

BLE.gatts_set_buffer(value_handle, len, append=False, /)

値の内部バッファサイズをバイト数で設定します。これにより、受信可能な最大の書き込みが制限されます。デフォルトは 20 です。

appendTrue に設定すると、すべてのリモート書き込みが現在の値に置き換えられるのではなく、追加されます。この方法では、最大で len バイトをバッファリングできます。 gatts_read を使用すると、読み取り後に値がクリアされます。この機能は、Nordic UART サービスのようなものを実装するときに役立ちます。

セントラルロール(GATT クライアント)

BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, /)

ペリフェラルに接続します。

成功すると _IRQ_PERIPHERAL_CONNECT イベントが発生します。

BLE.gap_disconnect(conn_handle)

指定した接続ハンドルを切断します。

成功すると _IRQ_PERIPHERAL_DISCONNECT イベントが発生します。

接続ハンドルが接続されていなければ False が返り、さもなければ True が返ります。

BLE.gattc_discover_services(conn_handle[, uuid])

サービスについて接続されたペリフェラルを問い合わせます。

オプションで照会するサービスの uuid を指定できます。

検出された各サービスについて _IRQ_GATTC_SERVICE_RESULT イベントが発生し、検索が完了すると _IRQ_GATTC_SERVICE_DONE になります。

BLE.gattc_discover_characteristics(conn_handle, start_handle, end_handle[, uuid])

指定した範囲のキャラクタリスティックについて接続されたペリフェラルを問い合わせます。

オプションで照会するキャラクタリスティックの uuid を指定できます。

任意のサービスのキャラクタリスティックを検索するには start_handle=1, end_handle=0xffff とします。

検出された各キャラクタリスティックについて _IRQ_GATTC_CHARACTERISTIC_RESULT イベントが発生し、検索が完了すると _IRQ_GATTC_CHARACTERISTIC_DONE になります。

BLE.gattc_discover_descriptors(conn_handle, start_handle, end_handle)

指定した範囲のディスクリプタについて接続されたペリフェラルを問い合わせます。

検出された各ディスクリプタについて _IRQ_GATTC_DESCRIPTOR_RESULT イベントが発生し、検索が完了すると _IRQ_GATTC_DESCRIPTOR_DONE になります。

BLE.gattc_read(conn_handle, value_handle)

指定したキャラクタリスティックあるいはディスクリプタについて接続されたペリフェラルにリモート読み込みを発行します。

値は有効であれば _IRQ_GATTC_READ_RESULT イベントが発生し、加えて _IRQ_GATTC_READ_DONE が発生します。

BLE.gattc_write(conn_handle, value_handle, data, mode=0, /)

指定したキャラクタリスティックあるいはディスクリプタについて接続されたペリフェラルにリモート書き込みを発行します。

引数 mode は書き込み動作を指定します。現在サポートされている値は次のとおりです:

  • mode=0 (デフォルト)は応答なしの書き込みです。書き込みはリモートペリフェラルに送信されますが、確認は返されず、イベントは発生しません。
  • mode=1 は応答付きの書き込みです。リモートプリフェラルはデータを受信したという応答/承認(acknowledgement)を送信するように要求されます。

リモートペリフェラルから応答を受信すると _IRQ_GATTC_WRITE_DONE イベントが発生します。

クラス UUID

コンストラクタ

class ubluetooth.UUID(value)

指定した value で UUID インスタンスを作成します。

value は次のいずれかです:

  • 16 ビット整数。たとえば 0x2908
  • 128 ビット UUID 文字列。たとえば '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'

定数

ubluetooth.FLAG_READ
ubluetooth.FLAG_WRITE
ubluetooth.FLAG_NOTIFY