Mac から BLE REPL で MicroPython を操作すると、

# 動機

[`MicroPytohn`](https://micropython.org/download/) をインストールした `Raspberry Pi Pico W` を Mac から `BLE REPL`しようとすると、幾つかのエラーに遭遇しました。
その時の対処法について残しておきます。

_ESP32他 の MicroPython でも同様と思われる。_

```text:環境 Mac
macOS        14.7.5
Python       3.11.11
upydev       0.4.3
upydevice    0.3.8
packaging    24.2
```

```text:環境 Raspberry Pi Pico W
MicroPython v1.24.1 on 2024-11-29; Raspberry Pi Pico W with RP2040
```


:::note warn
`BLE REPL`するための準備として、

1. [ここの](https://github.com/micropython/micropython/tree/master/examples/bluetooth) 次の3つのファイルを`Raspberry Pi Pico W`に配置しておく<br>`ble_advertising.py`, `ble_uart_peripheral.py`, `ble_uart_repl.py`<br>　

1. `Raspberry Pi Pico W`にて、`import ble_uart_repl; ble_uart_repl.start()`を実行しておく<br>（`main.py`に書いておけば(リ)ブート時に自動起動される）<br>　

1. Mac に `upydev`をインストールしておく<br>（`pip install upydev`を実行）
:::

# エラー 1

```terminal:BLEデバイスの検索にてエラー
% upydev scan -bl
Traceback (most recent call last):
  File "/opt/homebrew/bin/upydev", line 19, in <module>
    from packaging import version
ModuleNotFoundError: No module named 'packaging'
```

## 対処法

インストール済みででしたが、アンインストールして再インストールした。
（`pip install packaging -U` ライブラリの最新化で対処できたと思われる）

```shell
% pip install packaging

Requirement already satisfied: packaging in /opt/homebrew/lib/python3.11/site-packages (24.0)



% pip uninstall packaging

Found existing installation: packaging 24.0
Uninstalling packaging-24.0:
  Would remove:
    /opt/homebrew/lib/python3.11/site-packages/packaging-24.0.dist-info/*
Proceed (Y/n)? y
  Successfully uninstalled packaging-24.0


  
% pip install packaging  

Collecting packaging
  Downloading packaging-24.2-py3-none-any.whl.metadata (3.2 kB)
Downloading packaging-24.2-py3-none-any.whl (65 kB)
Installing collected packages: packaging
Successfully installed packaging-24.2
```


# エラー 2

```terminal:BLEデバイスの検索にて再びエラー
% upydev scan -bl        
Bluetooth Low Energy scan:
Scanning...
BleDevice/s found: 3
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃        NAME         ┃                   UUID                   ┃    RSSI    ┃                 Services                 ┃
┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃      mpy-repl       ┃   856C4A83-B2D3-339F-8CE2-xxxxxxxxxxxx   ┃    -56     ┃                                          ┃
┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
Traceback (most recent call last):
  File "/opt/homebrew/bin/upydev", line 1034, in <module>
    handle_action(args)
  File "/opt/homebrew/bin/upydev", line 499, in handle_action
    debugging_action(args, unknown_args, command_line=' '.join(sys.argv[1:]),
  File "/opt/homebrew/lib/python3.11/site-packages/upydev/debugging.py", line 1045, in debugging_action
    print('┃{0:^20} ┃ {1:^40} ┃ {2:^10} ┃ {3:^40} ┃'.format(dev.name, dev.address,
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unsupported format string passed to NoneType.__format__
```


## 対処法

上記エラーログにある`debugging.py`のソースコードを修正した。
（1行追加）

```diff_python:debugging.py#1045（フルパスはエラーログを参照）
+                   if dev.name is None: dev.name = '(None)'
                    print('┃{0:^20} ┃ {1:^40} ┃ {2:^10} ┃ {3:^40} ┃'.format(dev.name, dev.address,
                                                                            int(dev.rssi), ','.join(services)))
```

これで無事に検索できるようになった。

```terminal
% upydev scan -bl
Bluetooth Low Energy scan:
Scanning...
BleDevice/s found: 2
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃        NAME         ┃                   UUID                   ┃    RSSI    ┃                 Services                 ┃
┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃       (None)        ┃   4256B44A-5C48-2353-4E15-xxxxxxxxxxxx   ┃    -60     ┃                                          ┃
┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃      mpy-repl       ┃   856C4A83-B2D3-339F-8CE2-xxxxxxxxxxxx   ┃    -62     ┃                                          ┃
┗━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
```



# エラー 3

```terminal:BLEデバイスに接続時にエラー
% blerepl -t 856C4A83-B2D3-339F-8CE2-xxxxxxxxxxxx                    
Traceback (most recent call last):
  File "/opt/homebrew/bin/blerepl", line 63, in <module>
    dev.connect(show_servs=args.v, debug=args.v)
  File "/opt/homebrew/lib/python3.11/site-packages/upydevice/bledevice.py", line 1320, in connect
    return self.as_connect(**kargs).result()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/unsync/unsync.py", line 144, in result
    return self.concurrent_future.result(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/_base.py", line 456, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/opt/homebrew/lib/python3.11/site-packages/upydevice/bledevice.py", line 1309, in as_connect
    if hasattr(self.ble_client._peripheral, 'name'):
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'BleakClient' object has no attribute '_peripheral'
```


## 対処法

上記エラーログにある`bledevice.py`のソースコードを修正した。
（2行変更、2行追加）

```diff_python:bledevice.py#1305（フルパスはエラーログを参照）
    async def as_connect(self, n_tries=5, show_servs=True, debug=False):
        await self.connect_client(n_tries=n_tries, debug=debug)
        if self.connected:
            self.get_services(log=show_servs)
-           if hasattr(self.ble_client._peripheral, 'name'):
+           if hasattr(self.ble_client, '_peripheral') and hasattr(self.ble_client._peripheral, 'name'):
                if callable(self.ble_client._peripheral.name):
                    self.name = self.ble_client._peripheral.name()
-           else:
+           elif hasattr(self.ble_client, '_device_info') and hasattr(self.ble_client._device_info, 'get'):
                self.name = self.ble_client._device_info.get('Name')
+           else:
+               self.name = '(None)'
            if self.name in _WASPDEVS:
                self.len_buffer = 20
        else:
            raise DeviceNotFound('BleDevice @ {} is not reachable'.format(self.UUID))
```

これで無事に接続できるようになった。

```shell
% blerepl -t 856C4A83-B2D3-339F-8CE2-xxxxxxxxxxxx 
BleREPL connected

MicroPython v1.24.1 on 2024-11-29; Raspberry Pi Pico W with RP2040
Type "help()" for more information.

- CTRL-k to see keybindings or -h to see help
- CTRL-s to toggle shell/repl mode
- CTRL-x or "exit" to exit
rp2@e66138528394892c:~ $ (Ctrl+S)
>>> import sys
>>> sys.version
'3.4.0; MicroPython v1.24.1 on 2024-11-29'
>>> (Ctrl+X)
>>> closing...
>>>
logout
Connection to (None) closed.
% 
```

# しかし、

これで `BLE REPL` できるようになったが、まだ次のエラーが出る。


## エラー 4

```terminal:BLEデバイスの検索にてエラー
% upydev scan -bl
Bluetooth Low Energy scan:
Scanning...
BleDevice/s found: 1
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃        NAME         ┃                   UUID                   ┃    RSSI    ┃                 Services                 ┃
┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
/opt/homebrew/lib/python3.11/site-packages/upydev/debugging.py:1036: FutureWarning: BLEDevice.metadata is deprecated and will be removed in a future version of Bleak, use AdvertisementData instead
  if hasattr(dev, 'metadata'):
/opt/homebrew/lib/python3.11/site-packages/upydev/debugging.py:1037: FutureWarning: BLEDevice.metadata is deprecated and will be removed in a future version of Bleak, use AdvertisementData instead
  if isinstance(dev.metadata, dict):
/opt/homebrew/lib/python3.11/site-packages/upydev/debugging.py:1038: FutureWarning: BLEDevice.metadata is deprecated and will be removed in a future version of Bleak, use AdvertisementData instead
  if 'uuids' in dev.metadata.keys():
/opt/homebrew/lib/python3.11/site-packages/upydev/debugging.py:1041: FutureWarning: BLEDevice.metadata is deprecated and will be removed in a future version of Bleak, use AdvertisementData instead
  for serv in dev.metadata['uuids']]
/opt/homebrew/lib/python3.11/site-packages/upydev/debugging.py:1048: FutureWarning: BLEDevice.rssi is deprecated and will be removed in a future version of Bleak, use AdvertisementData.rssi instead
  int(dev.rssi), ','.join(services)))
```

_ググってみたが、有効な対処法が見つからず。
致命傷では無いので とりあえずスルー。_


##  エラー 5

⭐️ `REPL` で `Ctrl+D` すると例外が発生する。

```shell:BLE REPL でエラー
% blerepl -t 856C4A83-B2D3-339F-8CE2-xxxxxxxxxxxx                
BleREPL connected

MicroPython v1.24.1 on 2024-11-29; Raspberry Pi Pico W with RP2040
Type "help()" for more information.

- CTRL-k to see keybindings or -h to see help
- CTRL-s to toggle shell/repl mode
- CTRL-x or "exit" to exit
rp2@e66138528394892c:~ $ (Ctrl+S)
>>> (Ctrl+D) ⭐️

Unhandled exception in event loop:
  File "/opt/homebrew/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/events.py", line 84, in _run
    self._context.run(self._callback, *self._args)
  File "/opt/homebrew/lib/python3.11/site-packages/prompt_toolkit/input/vt100.py", line 162, in callback_wrapper
    callback()
  File "/opt/homebrew/lib/python3.11/site-packages/prompt_toolkit/application/application.py", line 714, in read_from_input_in_context
    context.copy().run(read_from_input)
  File "/opt/homebrew/lib/python3.11/site-packages/prompt_toolkit/application/application.py", line 694, in read_from_input
    self.key_processor.process_keys()
  File "/opt/homebrew/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_processor.py", line 273, in process_keys
    self._process_coroutine.send(key_press)
  File "/opt/homebrew/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_processor.py", line 188, in _process
    self._call_handler(matches[-1], key_sequence=buffer[:])
  File "/opt/homebrew/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_processor.py", line 323, in _call_handler
    handler.call(event)
  File "/opt/homebrew/lib/python3.11/site-packages/prompt_toolkit/key_binding/key_bindings.py", line 127, in call
    result = self.handler(event)
             ^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/upydev/shell/keybindings.py", line 766, in paste_mode_exit
    dev.reset()
  File "/opt/homebrew/lib/python3.11/site-packages/upydevice/bledevice.py", line 1558, in reset
    return self.un_reset(**kargs).result()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/unsync/unsync.py", line 144, in result
    return self.concurrent_future.result(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/_base.py", line 456, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.11/3.11.11/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/opt/homebrew/lib/python3.11/site-packages/upydevice/bledevice.py", line 1553, in un_reset
    await self.as_reset(**kargs)
  File "/opt/homebrew/lib/python3.11/site-packages/upydevice/bledevice.py", line 750, in as_reset
    await self.as_write_char(self.writeables['Nordic UART RX'],
  File "/opt/homebrew/lib/python3.11/site-packages/upydevice/bledevice.py", line 399, in as_write_char
    await self.ble_client.write_gatt_char(uuid, data)
  File "/opt/homebrew/lib/python3.11/site-packages/bleak/__init__.py", line 786, in write_gatt_char
    await self._backend.write_gatt_char(characteristic, data, response)
  File "/opt/homebrew/lib/python3.11/site-packages/bleak/backends/corebluetooth/client.py", line 326, in write_gatt_char
    await self._delegate.write_characteristic(
  File "/opt/homebrew/lib/python3.11/site-packages/bleak/backends/corebluetooth/PeripheralDelegate.py", line 196, in write_characteristic
    await future

Exception disconnected
Press ENTER to continue...
```

同時に、`Raspberry Pi Pico W` は リセット（ソフトブート）される。

```shell: Raspberry Pi Pico W
>>>
MPY: soft reboot
Unhandled exception in IRQ callback handler
Traceback (most recent call last):
  File "/lib/ble_uart_peripheral.py", line 66, in _irq
  File "/lib/ble_uart_peripheral.py", line 94, in _advertise
OSError: [Errno 19] ENODEV
MicroPython v1.24.1 on 2024-11-29; Raspberry Pi Pico W with RP2040
Type "help()" for more information.
>>> 
```

:::note alert
原因は、
REPL で `Ctrl+D` すると ソフトブートされる。これは正しい動作
⇨ ブートにより、BLE通信が切断される
⇨ Mac側の`blerepl`コマンドで例外が発生
:::


REPL で`Ctrl+D`しなければ問題ない。

**以上**