SwitchBot Plug Mini でBluetooth経由で消費電力を取り出す

## はじめに

SwitchBotから発売されたPlug MiniからBluetooth経由で消費電力を取得する方法についての知見について記載します。

以下のSwitchBotの公式が公開しているpython用のコードを利用できることが前提の説明となります

https://github.com/OpenWonderLabs/python-host

## Plug Miniについて

https://www.switchbot.jp/products/switchbot-plug-mini
> SwitchBotプラグミニはBluetoothとWi-Fiに対応可能なので、Wi-Fiチップのみのスマートプラグよりデバイスの追加と操作がより簡単に。

既存のSwitchBot PlugではWi-Fi経由でしかデータ取得や操作ができなかったところ，
Bluetoothによる操作にも対応したと謳っており,Wi-Fi環境がなくても使用できるようになった製品です．

また，On/Offしか操作できなかったPlugと比べて、消費電力をAPIを経由して取得可能になるなど,
消費電力を監視して，別のIoT機器を制御するような応用が効くようになりました.

私は,ロボット掃除機の充電台につけて,ロボット掃除機が帰ってきたら拭き掃除のロボットを発進させる機能を,
別メーカーのロボットで実現するために使用しています

## python-hostの改造

python3用の[switchbot_py2topy3.py](https://github.com/OpenWonderLabs/python-host/blob/master/switchbot_py2topy3.py)を改造します

SwitchBotのBluetoothでブロードキャストする機器からデータを取得する際,
[L77-L114](https://github.com/OpenWonderLabs/python-host/blob/d9e21e0514f181ce1dbf66b8a7189cd1b8af5ea0/switchbot_py2topy3.py#L77-L114)の処理で
`dev_type`で機器を判別してデータを取り出すのが一般的な方法なのですが,
Plug Miniはこの方法ではデータ取得できません

https://github.com/OpenWonderLabs/python-host/wiki/Plug-Mini-BLE-open-API

上記によると`UUID`や`macアドレス`を含んだブロードキャストの方でデータを配信していることから,
[L133-L134](https://github.com/OpenWonderLabs/python-host/blob/d9e21e0514f181ce1dbf66b8a7189cd1b8af5ea0/switchbot_py2topy3.py#L133-L134)に処理を追加することでデータを取得するように実装する必要があります.  


```python switchbot_py2topy3.py#L133-
elif desc == 'Manufacturer' and value[0:4] == company_id:
     mac = dev.addr
　　　#以下追記
     #`xx:xx:xx:xx:xx:xx`はPlugMiniのBluetoothのMacアドレスを小文字表記で`:`で区切った値
     if( mac  == "xx:xx:xx:xx:xx:xx"):
           mode = 0
           power = (int(value[24:28].encode('utf-8'), 16) & 0x7fff) / 10.0;
           sw = int(value[18].encode('utf-8'), 16 ) >> 3;
           param_list.extend([sw, power])
```

上記を追記しただけだとparam_listが[L113-114](https://github.com/OpenWonderLabs/python-host/blob/d9e21e0514f181ce1dbf66b8a7189cd1b8af5ea0/switchbot_py2topy3.py#L113-L114)の処理で初期化されてしまうので，
L113の手前に以下のコードを追加します.(plug miniの`dev_type`は`j` または `g` のようです)


```python switchbot_py2topy3.py#L113
　　　　　　　　　　　　# 追記ここから
                    elif (model == b'j') or (model == b'g') :
                        print("do nothing")
                    # 追記ここまで
                    else:
                        param_list[:] = []
```

次にデータを返すための整形を行います

まず[L44-L58](https://github.com/OpenWonderLabs/python-host/blob/d9e21e0514f181ce1dbf66b8a7189cd1b8af5ea0/switchbot_py2topy3.py#L44-L58)の部分で整形用の変数を定義します

```python switchbot_py2topy3.py#L44-
    def scan_loop(self):
        service_uuid = 'cba20d00-224d-11e6-9fb8-0002a5d5c51b'
        company_id = '6909'  # actually 0x0969
        dev_list = []
        bot_list = []
        meter_list = []
        curtain_list = []
        contact_list = []
        motion_list = []
        param_list = []
        plug_list = [] #追記

        pir_tip = ['No movement detected', 'Movement detected']
        hall_tip = ['Door closed', 'Door opened', 'Timeout no closed']
        light_tip = ['Dark', 'Bright']
        plug_sw = ['Off', 'On'] #追記
```

そして,[L140-L165](https://github.com/OpenWonderLabs/python-host/blob/d9e21e0514f181ce1dbf66b8a7189cd1b8af5ea0/switchbot_py2topy3.py#L140-L165)の処理でデータを返す部分を実装します．

```python switchbot_py2topy3.py#L156-
            elif dev_type == b'd':
                # TODO:
                # timeTirgger = datetime.datetime.now() + datetime.timedelta(0, params[3])
                # contact_list.append([mac, 'Contact', "%s, %s, %s, Last trigger: %s" %
                #                      (hall_tip[params[0]], pir_tip[params[1]], light_tip[params[2]], timeTirgger.strftime("%Y-%m-%d %H:%M"))])
                contact_list.append([mac, 'Contact', "%s, %s, %s" %
                                     (hall_tip[params[0]], pir_tip[params[1]], light_tip[params[2]])])
           #追記ここから 
           elif (dev_type == b'j') or (dev_type == b'g'):
                plug_list.append([mac, 'Plug', "%s, %.1fW", %
                                     (plug_sw[params[0]], params[1])])
　　　　　　 #追記ここまで

        print("Scan timeout.")
        #plug_listを追記
        return bot_list + meter_list + curtain_list + contact_list + motion_list + plug_list 
        pass

```

以上で編集は完了です.あとは `sudo python3 switchbot_py2topy3.py`を実行して以下のように表示されれば成功です

```bash
Scan timeout.
 0 ['6055f922d95a', 'Plug', 'On, 0.5W']
```