pythonでDyson扇風機の操作 やってみた

#はじめに
aloha !
本日（2020/8/17）、浜松では、国内最高の41.1度（タイ）を記録したそうです。
熱中症には十分ご注意ください。
そんな暑い中、我が家では数年前に購入したのDyson Pure Hot + Cool Link（扇風機）もエアコンと併用して大活躍です。
このDyson Pure Hot + Cool Linkをpython3からコントロールしてみようと思います。
どうやら、いろいろ検索してみたところ、MQTT（Message Queuing Telemetry Transport）を使うと実現できそうです。

#準備物
・Dyson Pure Hot + Cool Link (HP03)
・Python3が動くMacなど
・Wi-Fi（同一LANセグメント）
・Wireshark（必要であれば。フィルタをmqttにすると確認しやすいです）

#方針
いろいろ調べていくとDysonアカウント（メールアドレス）とパスワードが必要だそうです。
Dysonの公式アプリ（Dyson Linkアプリ）へ登録するとアカウントを発行できます。
このDysonアカウントとパスワードを非公開APIへhttpsで投げると登録済み機器のリストが取得でき、そこに接続用のユーザー名とパスワードが書かれています。

```json:response
{
  Device {
    _events: [Object: null prototype] {},
    _eventsCount: 0,
    _maxListeners: undefined,
    password:'*************************************************',
    username: '***-**-********',
    ip: null,
    url: null,
    name: 'キッチン',
    port: null,
    serial: '***-**-********',
    _MQTTPrefix: '520',
    _deviceInfo:
      { Active: true,
        Serial: '***-**-********',
        Name: 'キッチン',
        ScaleUnit: 'BRIDGE',
        Version: '21.04.03',
        LocalCredentials:'**************************************',
        AutoUpdate: true,
        NewVersionAvailable: false,
        ProductType: '455'
     }
  }
}
```

この中でMQTTの利用に必要になる情報は、次の3つです。

```
①username: '***-**-********'

②password:'*************************************************'

③ProductType: '455'
```

ただ、①は、本体のシールに書かれている「製品SSID」から、先頭の「DYSON-」と末尾の「-XXX」を除いた文字列ということがわかりました。
②も本体のシールに書かれている「製品Wi-Fiパスワード」を元に生成した文字列です。
具体的には、「製品Wi-Fiパスワード」をUTF-8でエンコードして、sha512でhash化し、base64エンコードしたものと同じでした。
次のようなコードで生成できます。

```python:hash_password.py
import hashlib
import base64

password = '<製品Wi-Fiパスワード>'
hash = hashlib.sha512()
hash.update(password.encode('utf-8'))
hash_password = base64.b64encode(hash.digest()).decode('utf-8')
print(hash_password)

```
これでMQTTを利用するためのパスワードが入手できます。
③についても実は、本体のシールに書かれています。「製品SSID」の末尾の「-」から後ろの3桁の数字です。

この①〜③の情報を使って、MQTTのトピックを組み立てるとDyson Pure Hot + Cool Linkの状態（温度、湿度、フィルターの寿命）や操作ができます。

状態を取得する場合のトピックはこんな感じです。

```
<③>/<①>/status/current
```


ここまで調べていて、この辺を全部やってくれる先人の知恵がいくつか見つかりましたので、参考にさせていただくことにします。

例えば、<a href="https://github.com/UBayouski/DysonPureLinkPlugin">UBayouski/DysonPureLinkPlugin</a>は、とても参考になりました。
では、実際にやってみましょう。

#手順
ターミナルで、保存用のディレクトリを作成します。

```
% cd ~
% mkdir dyson
% cd dyson
```

git cloneで上記のプロジェクトを取得します。

```
% git clone https://github.com/UBayouski/DysonPureLinkPlugin.git
```

DysonPureLinkPluginのディレクトリへ移動します。

```
% cd DysonPureLinkPlugin
```
必要なモジュールをインストールします。
例えば、

```
% pip3 install base64
% pip3 install pyyaml
% pip3 install paho-mqtt
% pip3 install pyqueue
```

などです。
次に設定ファイルを編集します。

```
% cp dyson_pure_link.yaml.example dyson_pure_link.yaml
% vi dyson_pure_link.yaml
```
dyson_pure_link.yamlファイルを開きます。

```yaml:dyson_pure_link.yaml

DYSON_PASSWORD: '<②>'
DYSON_SERIAL: '<①>'
DYSON_IP: '<IP_ADDR>'
DYSON_PORT: 1883 # Default port
DYSON_TYPE: 455 # Usully one of 455, 465, 475
```

これで準備が完了しました。

ただ、この``dyson_pure_link_device.py``は、python2系を前提として書かれているため、python3系で動かすためには、若干の修正が必要でした。

主な変更点は、次の通りです。

（１）6行目

```python:dyson_pure_link_device.py

from Queue import Queue, Empty
```
を

```python:dyson_pure_link_device.py

import queue, empty
```
へ変更しました。

（２）16行目〜19行目

```python:dyson_pure_link_device.py
self.connected = Queue()
self.disconnected = Queue()
self.state_data_available = Queue()
self.sensor_data_available = Queue()
```
を

```python:dyson_pure_link_device.py
self.connected = queue.Queue()
self.disconnected = queue.Queue()
self.state_data_available = queue.Queue()
self.sensor_data_available = queue.Queue()
```
へ変更しました。
これでとりあえず動くようになりました。


##状態の取得

以下のコマンドを実行するとDyson Pure Hot + Cool Linkの状態が取得できます。

```
% python3 run_plugin.py
```
以下のような応答があります。

```
Parsed config file:  {'DYSON_PASSWORD': '<②>', 'DYSON_SERIAL': '<①>', 'DYSON_IP': '<IP_ADDR>', 'DYSON_PORT': 1883, 'DYSON_TYPE': 455}
Connected:  True
Fan mode: FAN, Oscillation: OFF, Filter life: 1581, Standby monitoring: ON
Temperature: 81.94999999999999 F, Humidity: 72 %, Volatile Compounds: 4, Particles: 2
Disconnected:  True
```

モード（FAN）は、送風
首振り（Oscillation）は、OFF
温度は、81.94999999999999 F
（摂氏に変換すると81.94999999999999 - 32 / 1.8 = 27.75℃）
湿度は、72 %
フィルタの寿命？は、1581
ということがわかりました。

##操作
Dyson Pure Hot + Cool Linkを操作するためには、以下のコマンドが用意されています。
送風を開始する場合は、

```
% python3 run_plugin.py -fan FAN
```

送風を停止する場合は、

```
python3 run_plugin.py -fan OFF
```
となります。

詳しくは、<a href="https://github.com/UBayouski/DysonPureLinkPlugin">README.md</a>をご覧ください。

#まとめ
python3を使って、Dyson Pure Hot + Cool LinkをMQTTで状況取得＆操作することができました。
LANのみで利用することができることがわかりましたので、いろいろ使えそうですね。

Mahalo

##参考文献
<a href = "https://github.com/UBayouski/DysonPureLinkPlugin">https://github.com/UBayouski/DysonPureLinkPlugin</a>
<a href="http://aakira.hatenablog.com/entry/2016/08/12/012654">AAkira Developer Blog dyson扇風機 pure cool link をhack!</a>
<a href="https://github.com/CharlesBlonde/libpurecoollink">libpurecoollink</a>