はじめに
今回は前のBLEの実装作業の続きとして、BLEモジュールを使っていくつかのTipsを紹介します。本文にはubluetoothを使って送信時に必要なパケットの圧縮形式と受信で識別する時の識別子の話となります。
前回:
ESP32でBLEの実装作業【スキャン】
ESP32でBLEの実装作業【ブロードキャスト】
ESP32でBLEの実装作業【ペリフェラルとセントラル】
BLEのパケット
BLEは送信、および受信の際に圧縮されたC言語で定義したパケットで行われています。ustruct.unpack("<h", data)[0]によって圧縮されたデータを読み取ることができます。ここに注意してほしいのは最初の"<h"部分です。これはリトルエンディアンのshortと定義されているという意味であり、データを圧縮と解凍する時に参照する形式の一種です。基本的に送信側が圧縮するパケットの形式と受信側の解凍する形式は一致しなければなりません(自分は異なる形式をやった結果buffer too smallというエラー文が出ってきました)。
コード
ここにESP32でBLEの実装作業【ペリフェラルとセントラル】のスキャンプログラムを例として、注目してほしいのはdef_update_valueの三行目です。前述の通りでここに使っている解凍する形式は"<h"であるリトルエンディアンのshortとなります。
#パケットの解凍形式
class BLETemperatureCentral:
def __init__(self, ble):
self._ble = ble
self._ble.active(True)
self._ble.irq(self._irq)
self._reset()
def _update_value(self, data):
# Data is sint16 in degrees Celsius with a resolution of 0.01 degrees Celsius.
self._value = struct.unpack("<h", data)[0] / 100
return self._value
BLEの識別
BLEデバイスお互いに一般的にUUIDというサービス番号で識別していますが、しかし同じようなサービス番号を使うことも時々起きます。その解決の一種となるのは、UUIDだけではなく、サービスの名前も合併して一緒に識別子とします。
コード
ここにESP32でBLEの実装作業【ペリフェラルとセントラル】のスキャンプログラムを例として、注目してほしいのはdef _irqの5行目です。今はUUIDのみ識別子を使っています。この行の後ろにand decode_name(adv_data) == "好きな名前"と追加していればサービスの名前も一緒にif分に入れ、自分のデバイスしか識別できないようにすることができます。すると5行目下記の通りになります。
if adv_type in (_ADV_IND, _ADV_DIRECT_IND) and _ENV_SENSE_UUID in decode_services(adv_data) and decode_name(adv_data) == "好きな名前":
(もちろんペリフェラルの方からもnameの設定を"好きな名前"にしないとなりませんね)
_IRQ_SCAN_RESULT = const(5)
#EVENT中で識別子を書き換える
class BLETemperatureCentral:
def __init__(self, ble):
self._ble = ble
self._ble.active(True)
self._ble.irq(self._irq)
self._reset()
def _irq(self, event, data):
if event == _IRQ_SCAN_RESULT:
addr_type, addr, adv_type, rssi, adv_data = data
print('type:{} addr:{} rssi:{} data:{}'.format(addr_type, ubinascii.hexlify(addr), rssi, ubinascii.hexlify(adv_data)))
if adv_type in (_ADV_IND, _ADV_DIRECT_IND) and _ENV_SENSE_UUID in decode_services(adv_data) and decode_name(adv_data) == "好きな名前":
# Found a potential device, remember it and stop scanning.
self._addr_type = addr_type
self._addr = bytes(
addr
) # Note: addr buffer is owned by caller so need to copy it.
self._name = decode_name(adv_data) or "?"
self._ble.gap_scan(None)