質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

コールバック

コールバックは他のコードに引数として渡されるコードのことを指します。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

6143閲覧

bluepyで、ペアリング成功、ペアリング失敗、ペアリング切断の検出を行いたい

eleele28

総合スコア18

Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

コールバック

コールバックは他のコードに引数として渡されるコードのことを指します。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/02/10 09:02

編集2021/02/10 09:40

わからないこと

bluepyライブラリを使って、ペアリング成功、ペアリング失敗、ペアリング切断の検出を行いたいのですが、実現法が分からず困っています。

実現したいこと

RasberryPi Zero WをBLEセントラルにしたいと考えています。

今回はbluepyを使って、セントラルとしての機能を作成します。
接続相手のペリフェラルのMACアドレスは今回決め打ちであるため、
btle.Peripheral()を引数無しでインスタンス化した後、
Peripheral.connect(macAdrr)を呼び出してペリフェラルに接続を行います。

このあと、
・ペアリングが成功した時
・ペアリングが失敗した時
・ペアリング成功し、通信を行っている最中に相手が落ちてしまうなどしてペアリングが切断されてしまった時
それぞれのイベントをハンドリングし、適宜処理を行いたいと考えています。

認識していること

通知イベントのハンドルは、DefaultDelegateクラスを継承したクラスを定義し、
オーバーライドしたhandleNotification()でハンドリングすることで行うのはよく理解できました。
ただ、handleNotification()はあくまで「ペリフェラルから通知を受信したとき」にコールバックされるものであり、
接続・切断の発生といった、通信モジュールの状態変化の際にコールバックがあるものではないと認識しています。

コードイメージ

まだ設計段階なので本物のコードはないのですが、実装イメージとしては以下の通りです。
(bluepyのコード例を借りて即興で作りました)
ペリフェラルにコネクトした後メインループに入って他タスクからのキューメッセージを待受け、
他タスクからメッセージが来たらペリフェラルにWrite要求を発行します。
「p.connect()の失敗or成功」及び「メインループに入った後のペアリング切断」をなんらかの方法でハンドリングしたいです。

Python

1import btle 2 3# 通知をハンドルするデリゲート用クラス 4class MyDelegate(btle.DefaultDelegate): 5 def __init__(self, params): 6 btle.DefaultDelegate.__init__(self) 7 # ... initialise here 8 9 def handleNotification(self, cHandle, data): 10 # ペリフェラルからの通知受信時に行う処理をここに書く 11 # (通信モジュールの状態変化はここでハンドルすることはできない?) 12 13# 他タスクスレッド生成などの初期処理がこのあたりに記述される。今回は省略 14 15# インスタンス生成 16p = btle.Peripheral() 17 18# 通知ハンドル用クラスをセット 19p.withDelegate( MyDelegate(params) ) 20 21# ペリフェラルにコネクト 22p.connect('XX:XX:XX:XX:XX:XX') 23 24# サービスを取得(サービスは1つだけの想定です) 25svc = p.getServiceByUUID( service_uuid ) 26 27# キャラクタリスティックを取得(キャラクタリスティックも1つだけの想定です) 28ch = svc.getCharacteristics( char_uuid )[0] 29 30# Main loop -------- 31while True: 32 # ここで他タスクからのキューメッセージをブロッキングで待つ 33 event_id = waitMsg() 34 35 if event_id == DATA_SEND_REQ_EVENT: 36 # データWrite要求発行(今回の通信はセントラル⇒ペリフェラル方向のみです) 37 ch.write( data ) 38 39

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2021/02/10 09:13

コードを提示しましょう
guest

回答1

0

ベストアンサー

・「接続(establish connection)の成功/失敗のハンドリング」ですが、
「接続相手のペリフェラルのMACアドレスは今回決め打ちである」とのことなので
一例として、下記のような動作を行う関数connect_with_retryを考えてみました。
1. 接続先ペリフェラルのMACアドレスを指定して接続を試みる。
2.接続開始から、指定した時間(例:10秒)経過しても接続できない場合は、指定した回数接続を試みる。
3.指定した回数(例:3回)行っても、接続できない場合は、「失敗」を返す。
4.指定した回数内で接続に成功した場合は「成功」を返す

def connect_with_retry(p: btle.Peripheral, macaddr: str, timeout=None, retry_count=1) -> bool: for _ in range(retry_count): try: p.connect(macaddr, timeout=timeout) print("接続に成功しました。") return True except btle.BTLEDisconnectError: print("タイムアウトしました。接続を再試行します。") else: print("規定のリトライ回数を超過しました。接続に失敗しました。") return False # 使用側 p = btle.Peripheral() p.withDelegate( MyDelegate(params) ) if connct_with_retry(p, 'XX:XX:XX:XX:XX:XX', timeout=10, retry_count=3) == False: # 接続失敗時の処理

・「ペアリング成功し、通信を行っている最中に相手が落ちてしまうなどしてペアリングが切断されてしまった時」
これについては一定間隔で btle.PeripheralオブジェクトのgetState()関数を呼ぶようにすればよいと思います。
getState()関数を呼んだ段階で、仮に通信が切断されてしまっている場合は、、btle.BTLEDisconnectErrorが発生するはずなので、try...exceptで補足し、execept節に適切な処理を書けばいいのではないでしょうか。

投稿2021/02/12 07:02

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

eleele28

2021/02/15 01:46

ありがとうございます! メソッド読んだ後に発生する例外で判断するんですね! 通知受信時のhandleNotification()みたいに非同期イベントとしてハンドリングすることは不可能なんでしょうか…?
退会済みユーザー

退会済みユーザー

2021/02/15 03:28 編集

>通知受信時のhandleNotification()みたいに非同期イベントとしてハンドリングする ここでの「非同期イベントとしてハンドリングする」とは厳密にはどのような意味でしょうか? 仮に(”非同期イベント"の定義は無視するとして)「通知受信時のhandleNotification()みたいにハンドリングする」の意味を 「通信中に切断等が発生した場合のbtle.BTLEDisconnectError等を、処理ごとにtry...catch 節で素直に捕捉して処理するのではなく、MyDelegateクラスの中に関数を用意して、その関数の中で処理したい」という意味であれば、 元のbtle.pyのBluepyHelper._waitResp関数に手を加えるか、例外発生時の処理を捕捉する関数をデコレータとして作り、メイン処理の関数をそのデコレータでラップすることで対応できるとは思います。
eleele28

2021/02/15 03:40

言葉が足りず申し訳ありません。 まさにそういうイメージです。 丁寧に説明して頂き、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問