3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ラズパイをBLEのセントラル, AE-TYBLE16をペリフェラルとしてSPP的に通信

Last updated at Posted at 2019-01-30

これまでのあらすじ

以前こちらの私の記事で ESP32-DevKitC と AE-TYBLE16 (with マイコン)の通信をしたが、最近導入したラズパイ3B でもしてみむとてするなり。python で。

おことわり

TAIYO YUDEN Original Service UUID、TAIYO YUDEN Characteristic UUID については、公開されている brief data report には記載がなく、購入者向けの data report には載っているので、このサイトの記事では記載しないこととします。Source Code of "Terminal Application for Android" の Terminal.java に書いてありますので、そちらをご参照下さい。
(公開されているサンプルコードに書いてあるとはいえ今後公開停止されることもあろうかと言う事で)
また、これらUUIDに対応する handle の値も固定であるように思われますが、UUIDを知らないと調べられない情報なので、そのものズバリの数値は使わず仮の数字で書いています。

解りにくくてすみませんが、権利侵害とかしたくないので。

2019/3/19 更新: CCCD(Client Characteristic Configuration Descriptor) は 「Bluetooth SIGという団体にて標準で定義されているuuid」なので伏せるのをやめました。

AE-TYBLE16側

こちらの私の記事で書いたような「AE-TYBLE16 + マイコン(Arduino Nanoや互換回路)」という構成です。ピンアサインとかその辺は前の記事の通りです。

Raspberyy Pi3 への pybluez の入れ方(なお使わなかった模様)

ラズパイ3B にbluez は既に入ってたが、入ってなければ

$ sudo apt-get install bluez

んで、参考記事1を参考に

$ sudo apt-get install python-dev libbluetooth3-dev libglib2.0 libboost-python-dev libboost-thread-dev
$ sudo pip install pybluez
$ sudo pip install gattlib

これだけでコマンド叩くとエラーが出たのでまた調べて参考記事2 を見て、

$ sudo systemctl daemon-reload
$ sudo service bluetooth restart

とかして確認コマンド下記で対象デバイスが見つかればOK。

$ sudo hcitool lescan 

やっぱ pybluez やめた、bluepy にする!

サンプルプログラムで丁度いいのが、参考記事3で、bluepy って奴を使ってるので、そっちにした!(笑)

$ sudo pip install bluepy

pybluez の準備で入れた奴のうちどれが必要なのかわからないので、こんな酷い記事で本当にごめんなさい。

ハンドルって何だ?調べないと!

前述参考記事3のとおりにプログラムを…… writeCharacteristic のパラメータの handle ってなんじゃらほい?UUIDとかそういう奴はおらんの???

(2019/3/19 追記: もうちょい詳しく記事にしました。 https://qiita.com/ajtajta_j/items/ab0b09edf45976af0094
また、本記事も曖昧だった部分をupdateして、ちゃんと特定できるような書き方にしました。)

調べ方は参考記事4を参考に、gatttoolでとりあえずInteractiveモード起動して connect して char-descで handle - UUID 対応リストを出す。(下記は仮の数字で実際の出力とは違います)

pi@raspberrypi:~/TYBLE $ gatttool -b XX:XX:XX:XX:XX:XX -t random -I
[XX:XX:XX:XX:XX:XX][LE]> connect
Attempting to connect to XX:XX:XX:XX:XX:XX
Connection successful
[XX:XX:XX:XX:XX:XX][LE]> char-desc
handle: 0x0001, uuid: <UUID1>
handle: 0x0002, uuid: <UUID2>
handle: 0x0003, uuid: <UUID3>
handle: 0x0004, uuid: <UUID4>
handle: 0x0005, uuid: <UUID5>
handle: 0x0006, uuid: <UUID6>
handle: 0x0007, uuid: <RX_CHARACTERISTIC_UUID>
handle: 0x0008, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0009, uuid: <UUID7>
handle: 0x000a, uuid: <TX_CHARACTERISTIC_UUID>
handle: 0x000b, uuid: <UUID8>
handle: 0x000c, uuid: <UUID9>
handle: 0x000d, uuid: <UUID10>
handle: 0x000e, uuid: <UUID11>
handle: 0x000f, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0010, uuid: <UUID12>
handle: 0x0011, uuid: <UUID13>
handle: 0x0012, uuid: <UUID14>
handle: 0x0013, uuid: 00002902-0000-1000-8000-00805f9b34fb
[XX:XX:XX:XX:XX:XX][LE]> exit

(gatttool:18268): GLib-WARNING **: Invalid file descriptor.

pi@raspberrypi:~/TYBLE $

よく見ると太陽誘電サービスの UUID に対応するハンドルがわかる。
以前の私の記事 にも書きました(いや書いてないけど)が、UUID はサンプルコード (Android Central用なら Terminal.java )に書いてある4つ

Terminal.java
    private static final UUID CCCD                  = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    public static final UUID TY_SERVICE_UUID        = UUID.fromString("太陽誘電のサイトのサンプルファイルでご確認ください");    // Taiyo Yuden Service UUID
    public static final UUID RX_CHARACTERISTIC_UUID = UUID.fromString("太陽誘電のサイトのサンプルファイルでご確認ください");    // Taiyo Yuden Rx Characteristic
    public static final UUID TX_CHARACTERISTIC_UUID = UUID.fromString("太陽誘電のサイトのサンプルファイルでご確認ください");    // Taiyo Yuden Tx Characteristic

これら4つのうち、UUID CCCD ってのが、ペリフェラルからの notify を enable するための descriptor で、char-desc の結果には同じのが3つあったので仮にhandleを 0x0008, 0x000f, 0x0013 とします(実際は違うので各自確認してください)
RX_CHARACTERISTIC_UUID ってのがペリフェラルからの read のための奴で、これがhandle 0x0007 、TX_CHARACTERISTIC_UUID ってのがペリフェラルへの write のための奴で、0x000a とします(これらも実際は違うので以下同文)

CCCD が3つありますが、RX_CHARACTERISTIC_UUID の後にある一番近い奴が RX_CHARACTERISTIC の通知を有効にするための CCCD です。上記例だと0x0008 です。Write のほうはそのまま 0x000a ですので、

> char-write-req 0x0008 0100
> char-write req 0x000a test_string

ってやって送信先で受信できたり、相手方からのnotify が届けば「ハンドルこれだった!」ってなります。(上記例は実際と違う数値にしてあるので、しつこいけど自分で確認してください。)

やっとプログラム.py

rpi2aetyble16.py
# -*- coding: utf-8 -*-

from bluepy.btle import Peripheral
import bluepy.btle as btle
import binascii
import sys

devaddr =  "xx:xx:xx:xx:xx:xx" # BLE ペリフェラルのアドレス

class MyDelegate(btle.DefaultDelegate):
    def __init__(self, params):
        btle.DefaultDelegate.__init__(self)

    def handleNotification(self, cHandle, data): # notify callback
        sys.stdout.write( data ) #受信文字列を表示するだけ

class MyPeripheral(Peripheral):
    def __init__(self, addr):
        Peripheral.__init__(self, addr, addrType="random")

def main():
    # 初期設定
    perip = MyPeripheral(devaddr)
    perip.setDelegate(MyDelegate(btle.DefaultDelegate))

    # notifyを有効にする
    perip.writeCharacteristic(0x0008, "\x01\x00", True)  # 0x0008 は自分で調べたCCCD ハンドルで
    #文字列の送信例
    perip.writeCharacteristic(0x000a, "2001/01/01 00:00:01\r\n") # 0x000a は自分で調べたハンドルで

    # データを受信し続ける
    while True:
        perip.waitForNotifications(1.0)

if __name__ == "__main__":
    main()

めっちゃシンプルやん……UUID4つのうち2つの handle 調べて書いとけばUUIDだなんだやらなくて済むやん……

これ、自作時計の時刻設定用プログラムの素なので、日付と時刻を通知しています。ペリフェラルは受領したら返事よこすようになっています。2つのAE-TYBLE16 で試しましたが、devaddr の Bluetooth address のみ変えて handle その他全部一緒で使えています。

実用プログラムとしては datetime.now() などで現在時刻取ったり、時刻設定以外の命令飛ばしたり、パラメータで2つのアドレス切り替えたりもしてますがこの記事には関係無いので割愛。キモの部分はすぐ忘れそうな自分のために qiita に投稿して完了。

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?