micropython / micropython/micropython-lib
[aioble] After timeout, reconnection is successful. (Peripherals are always powered off)
オープン
まだ誰も着手していません。
- 主要言語
- Python
- スター
- 2.9k
- フォーク
- 1.1k
- 平均マージ
- 7日 6時間
- マージ済み PR(30日)
- 3
説明
The other device is powered off. However, after a connection timeout, it appears to be connected when retried. In fact, it is failing.
I'm not a native speaker, so sorry if my writing is wrong.
-
Environment
- Raspberry Pi Pico W with RP2040
- MicroPython v1.24.0 on 2024-10-25
- IDE:Thonny
-
Steps to reproduce
- Power off the peripheral device.
- Timeout occurs when trying to connect.
- Retry and the connection succeeds. (It actually fails.)
-
Code used for testing
from micropython import const
import asyncio
import aioble
# import test_aioble as aioble
import sys
_TARGET_DEVICE_ADDR = const("d7:de:4c:f4:56:e5")
async def gather(ai):
ret=[]
async for x in ai: ret.append(x)
return ret
async def device_details(connection):
if connection is None:
return
try:
services = await gather(connection.services())
except asyncio.TimeoutError as e:
print("Timeout. (discovering services)")
sys.print_exception(e)
except Exception as e:
print("Error (discovering services): {}".format(e))
sys.print_exception(e)
else:
if services is None or len(services) <= 0:
print("\n\"Service\" not found.")
return
for s in services:
print("\t", s)
async def print_details(device):
connection = None
# connecting to device
try:
print("\nConnecting to {} ... ".format(device), end="")
connection = await device.connect(timeout_ms=2000)
except asyncio.TimeoutError as e:
print("Timeout.")
sys.print_exception(e)
except Exception as e:
print("Error: {}".format(e))
sys.print_exception(e)
else:
print("Connected.")
await device_details(connection)
await connection.disconnect()
async def main():
device = aioble.Device(aioble.ADDR_RANDOM, _TARGET_DEVICE_ADDR)
while True:
await print_details(device)
r = input("\nenter return (to retry) / q(uit). > ").strip()
if r.upper() == "Q":
sys.exit(0)
asyncio.run(main())
- Output
MPY: soft reboot
MicroPython v1.24.0 on 2024-10-25; Raspberry Pi Pico W with RP2040
Type "help()" for more information.
>>>
>>> %Run -c $EDITOR_CONTENT
MPY: soft reboot
Connecting to Device(ADDR_RANDOM, d7:de:4c:f4:56:e5) ... Timeout.
Traceback (most recent call last):
File "<stdin>", line 47, in print_details
File "aioble/device.py", line 149, in connect
File "aioble/central.py", line 140, in _connect
File "aioble/device.py", line 94, in __exit__
TimeoutError:
enter return (to retry) / q(uit). >
Connecting to Device(ADDR_RANDOM, d7:de:4c:f4:56:e5, CONNECTED) ... Connected.
Error (discovering services): can't convert NoneType to int
Traceback (most recent call last):
File "<stdin>", line 24, in device_details
File "<stdin>", line 14, in gather
File "aioble/client.py", line 128, in __anext__
File "aioble/client.py", line 120, in _start
File "aioble/client.py", line 193, in _start_discovery
TypeError: can't convert NoneType to int
enter return (to retry) / q(uit). >
- How to fix it
I added exception handling because of the following problem. (It is not a good idea to fix it in this place.)- When the timeout occurs, the variable "_connection" in aioble is not in the correct state.
- When the timeout occurs, the internal state of the module "bluetooth" seems to remain connected.
# https://github.com/micropython/micropython-lib/blob/master/micropython/bluetooth/aioble/aioble/central.py#L107
async def _connect(
connection, timeout_ms, scan_duration_ms, min_conn_interval_us, max_conn_interval_us
):
<< Omitted >>
try:
with DeviceTimeout(None, timeout_ms):
ble.gap_connect(
device.addr_type,
device.addr,
scan_duration_ms,
min_conn_interval_us,
max_conn_interval_us,
)
# Wait for the connected IRQ.
await connection._event.wait()
assert connection._conn_handle is not None
# Register connection handle -> device.
DeviceConnection._connected[connection._conn_handle] = connection
except:
device._connection = None
ble.gap_connect(None)
raise
finally:
# After timeout, don't hold a reference and ignore future events.
_connecting.remove(device)
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
aioble/central.py:_connect から始め、aioble/device.py と aioble/client.py の関連する状態処理を確認します。ペリフェラルの電源をオフにした状態で、提供されたスクリプトを使って Raspberry Pi Pico W 上で再現し、その後、接続を再試行します。タイムアウトによって誤った接続済み状態が残らず、再試行が接続済みとして進行せず、サービスディスカバリ中にも失敗しなければ完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- python
- 領域
- embedded-iot, networking
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 45/100