M5Stack UIFlow v1.7.2 での Blynk の不具合(一部対応済)

【2021/03/20更新】3/18 に対応されたのは Blockly から生成される MicroPython のコードの問題「1. イベント契機の処理が実行されない」のみで、他の不具合については解消していないのでタイトルは「一部対応済」としました。

【2021/03/18更新】バージョンは v1.7.3 のままですが、Web側の対応で Blockly から生成される MicroPython のコードが修正され、問題なく動作するようになりました。

【2021/03/12更新】UIFlow v1.7.3 がリリースされていますが、Blynk の Blockly から生成される MicroPython のコードは更新されていませんでした。

#概要

M5Stack UIFlow では BLE接続で Blynk を使用することができますが、最新版の v1.7.2(1.7.1でも)ではいくつか不具合があったため、その回避策についてのまとめです。以前から Twitter でも呟いて M5Stack の中の人にも問題は認識してもらえたようなので UIFlow側で対応されるのを期待しているのですが、春節の休みにも入ってまだしばらくかかりそうな気もするので、ここでまとめておきます。

不具合は以下の３点です。
1. [イベント（Read、Write、Connected、Disconnected）契機の処理が実行されない](#1-イベント契機の処理が実行されない)
2. [virtual_write を連続して呼び出した場合に２つ目以降が受け取られない](#2-virtual_write-を連続して呼び出した場合に２つ目以降が受け取られない)
3. [Blynk アプリからのBLE接続時「Select BLE Device」で表示される名前が「ESP32」になる](#3-blynk-アプリからのble接続時select-ble-deviceで表示される名前がesp32になる)

#環境

- M5Stack Core2 (UIFlow 1.7.2)
- iOS 14.4
- iOS Blynk 2.26.5

#不具合

### 1. イベント契機の処理が実行されない

以下のようなイベント契機の処理を Blockly で作成します。
![スクリーンショット 2021-02-11 23.08.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133064/ff3f28dd-c264-5367-0b69-88179aaac065.png)

ことのき生成される MicroPython のコードは以下の通り。イベント契機で呼び出されるべき関数がすべて同じ blynk_write となっており、正しくイベント処理が行われる気がしませんし、実際関数が呼ばれません。

```python
from m5stack import *
from m5stack_ui import *
from uiflow import *
from ble import blynk

screen = M5Screen()
screen.clean_screen()
screen.set_screen_bg_color(0xFFFFFF)

vr = None
count = None
vw = None
value = None

def blynk_write():
  global vr, count, vw, value
  print('connected')

  pass

def blynk_write():
  global vr, count, vw, value
  print('disconnected')

  pass

def blynk_write(*args):
  global vr, count, vw, value
  vr = args[0]
  count = count + 1
  print([vr, count])
  blynk.virtual_write(int(vr), count)

  pass

def blynk_write(*args):
  global vr, count, vw, value
  vw, value = args[0], args[1]
  print([vw, value])

  pass

blynk.init('Blynk Test', '...token...', blynk.BLE)
blynk.handle_event(blynk_write, 'connected')
blynk.handle_event(blynk_write, 'disconnected')
blynk.handle_event(blynk_write, 'write v*')
blynk.handle_event(blynk_write, 'read v*')
count = 0

# 確認用にcallback関数の定義状態を出力
for k in blynk._blynk.callbacks:
  print(k, blynk._blynk.callbacks[k])
```

callback関数の定義は以下のようにひとつであり、キーに関数が、値に「read v*」が設定されている状態です。

```
<function blynk_write at 0x3f844d10> read v*
```

1.7.1 以降で UIFlow での MicroPython コードの生成と Blynk 関連ライブラリとで整合性が取れていないようで、いろいろ試行錯誤の結果たどりついたのが、以下のようなコードです。イベント契機に呼び出される関数名を一意にし、blynk.handle_event の引数を逆にしています。

```python
from m5stack import *
from m5stack_ui import *
from uiflow import *
from ble import blynk

screen = M5Screen()
screen.clean_screen()
screen.set_screen_bg_color(0xFFFFFF)

vr = None
count = None
vw = None
value = None

def blynk_connected():
  global vr, count, vw, value
  print('connected')

  pass

def blynk_disconnected():
  global vr, count, vw, value
  print('disconnected')

  pass

def blynk_read(*args):
  global vr, count, vw, value
  vr = args[0]
  count = count + 1
  print([vr, count])
  blynk.virtual_write(int(vr), count)

  pass

def blynk_write(*args):
  global vr, count, vw, value
  vw, value = args[0], args[1]
  print([vw, value])

  pass

blynk.init('Blynk Test', '...token...', blynk.BLE)
blynk.handle_event('connected',    blynk_connected)
blynk.handle_event('disconnected', blynk_disconnected)
blynk.handle_event('write v*',     blynk_write)
blynk.handle_event('read v*',      blynk_read)
count = 0

# 確認用にcallback関数の定義状態を出力
for k in blynk._blynk.callbacks:
  print(k, blynk._blynk.callbacks[k])
```

callback関数の定義は以下のようにイベント種別がキーとなり、関数が値として登録されています。

```
disconnected <function blynk_disconnected at 0x3f844800>
write v* <function blynk_write at 0x3f844c10>
connected <function blynk_connected at 0x3f8447e0>
read v* <function blynk_read at 0x3f844b30>
```

最初、UIFlow 1.7.0 を試したときは以下ような blynk.init() が最初にあり、デコレータによってイベント関数を定義する方式でした。この場合は関数名が同じ（すべてblynk_write）でもデコレータの直後の関数の定義が使用されるため、一応動いていました。
1.7.2 でも以下のような使い方はできました。1.7.1 から Blockly から生成されるコードが変更になったようですが、なぜ変更になったのかは謎です。

```python
blynk.init('Blynk Test', '...token...', blynk.BLE)

@blynk.handle_event('connected')
def blynk_write():
  print('connected')
  pass

@blynk.handle_event('disconnected')
def blynk_write():
  print('disconnected')
  pass
```

### 2. virtual_write を連続して呼び出した場合に２つ目以降が受け取られない

以下のように複数の blynk.virtual_write() を連続で呼び出した場合に Blynkアプリ側で２つ目以降のデータを受け取ることができませんでした。Blynkアプリ側からの読み出し要求に対して値を返す場合はあまり問題にならないかもしれませんが、M5Stack側のタイマー等の契機で複数の値を送るときにこの問題が発生しました。

```python
blynk.virtual_write(1, data1)
blynk.virtual_write(2, data2)
```

間隔(50msとか)を空けて送れば受け取ることができたりしたのですが、探していて以下のライブラリにたどり着きました。
https://github.com/vshymanskyy/blynk-library-python/blob/master/examples/hardware/PyCom_BLE.py

このライブライの以下の部分が virtual_write で呼び出される部分であり、virtual_write だけでは送信されず送信バッファに結合されているだけです。そして定期的に呼び出されている run() の中で実際の送信が行われています。

```python
    def _write(self, data):
        self.bout += data
```

それでは、ということで以下のように blynk.virtual_write() の直後に blynk._blynk.run() を呼び出し強制的に送信するようにしたところ Blynkアプリ側でも連続したデータが受けられるようになりました。Blynkアプリ側が結合されたデータを受けられないというのも問題かと思いますが、そちらの対応を待つこともできないので。

```python
blynk.virtual_write(1, data1)
blynk._blynk.run()
blynk.virtual_write(2, data2)
blynk._blynk.run()
```

### 3. Blynk アプリからのBLE接続時「Select BLE Device」で表示される名前が「ESP32」になる

Blynk アプリからのBLE接続時「Select BLE Device」で表示される名前が「ESP32」なってしまい、blynk.init() で指定した名前が表示されないことがあります。これについては以下の issue が関連しているのかと思います。

[micropython issue #6297 BLE.active() change gap_name to "ESP32"](https://github.com/micropython/micropython/issues/6297)

以下のように blynk.blynkBLE.ble.config で gap_name を指定することで、BLE接続時の表示も指定したものになります。

```python
blynk.init('Blynk Test', '...token...', blynk.BLE)
blynk.blynkBLE.ble.config(gap_name='Blynk Test')
````