dyson扇風機 pure cool link をhack!

dysonのIoT扇風機を自由自在に操作する!!

roombaのライバルとして発売されたロボット掃除機dyson 360eyeで、ついにIoT市場に参戦したdyson
高級扇風機市場を独占していた羽なし扇風機にも2016年モデルからついにIoTに対応しました。
しかし、この製品を含むdysonAPIを公開していません。
せっかくセンサーもあって操作が出来る環境があるのに操作出来ないのはエンジニアにとっては物足りない!!
ということで、本記事ではdyson pure cool linkをhackしてセンサーデータの取得・扇風機の操作を目指します。

※ 今回行った内容は公式に許可されているものではありません。
全て自己責任でお願いします。著者は一切の責任を負いません。

本体との接続方法

はじめ、dyson pure cool link(以下dyson)は入力のインタフェースがボタンしか無い為アプリ側との接続はp2pかと思っていたのですが、
実際はdyson自体を自宅のLANに接続して操作するようです。 (取得したセンサーデータはdyson社に全部送られてるのでしょう...)

  • 手順
    • 自宅の無線LANに接続している端末でアプリを立ち上げます
    • dysonのボタンを5秒長押しして本体のwifiをonにします。この時にdysonのアクセスポイントが立ち上がります
    • 無線LANSSID, passwordをアプリ側に入力します。本来ならwifiのパスワードを入れる意味はわかりませんが、おそらくここでdyson無線LANに接続させられるようパスワードを入力させるのだと思います(ちなみに5GHzの周波数には繋がらないっぽいです)
    • アプリがdysonを認識し、数分するとdysonがLAN接続されます。同時にdysonのアクセスポイントは消えました。アプリとの初回接続時の為のみっぽいです

以上でdysonが自宅のLANに接続され、hackの準備が整いました!

APIの分析

まず通信方法を探るためにpacket captureします

  • 使用ソフト

android端末でtPacketCaptureを使用してpacket captureし、dyson linkを起動します 以下のホーム画面にアクセスした際のpcapファイルを取得します

f:id:AAkira:20160812011328p:plain

androidでcaptureしたpcapファイルをwiresharkで開くと以下の様な画面になります

f:id:AAkira:20160811200817p:plain

しかし、これだとどのpacketが何の通信かわからないので、nmapを使用してdysonのip addressを特定します。 コマンドは省略しますが、dyson特定後いろいろポートスキャンしてみました。(一部省略)

Host is up (0.011s latency).
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: D-Link DI-524 wireless broadband router (98%), Denon CEOL RDC-N8 audio system (95%), Yamaha RX-S600 or Denon AVR-1912 or AVR-2312 audio receiver (95%), KCorp KLG-575 WAP (95%), Sony CMT-MX700Ni audio player (95%), Virdi 3000 fingerprint access controller (95%), Yamaha RX-A2040 AV receiver (95%), D-Link DI-524 or WBR-2310 wireless broadband router (95%), D-Link DWL-900AP+, Planet WAP-1966, or USRobotics USR5450 WAP (95%), D-Link DWL-G810 WAP (95%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 1 hop

OSは独自の何か使ってるんですかね、汎用OSでは無さそうです
ip addressが特定出来たのでwiresharkでフィルタリングします (フィルタリング欄にip.addr == *.*.*.*を入力)

f:id:AAkira:20160811200350p:plain

フィルタリングをすると色々見えてきます
どうやらプロトコルはMQTTと呼ばれるIoTに適したシンプルで軽量なプロトコルを使ってるようです
MQTT使ってる端末に初めて遭遇したのですが意外に使われてるんですね
また下にあるポート番号を覚えておいて下さい
自分の環境では1883が使われているのですが、全員共通のポートかはわかりません

認証情報を取得する

今回のdyson側と呼び出し、読み取り側の通信は認証されていました。
通信にはパスワードが必要なのでandroid側でキャプチャしたパケットからパスワードを抜き取ります
MQTTの認証はconnect commandで行われるので、connectしているパケットを探します
wiresharkで見るとこんな感じ

f:id:AAkira:20160811222214p:plain

ペイロードを見るとUser namePasswordがわかります
この組み合わせは、通信に使うので控えておいて下さい

f:id:AAkira:20160811222901p:plain

実際に通信をする

認証情報が取得出来たので実際にdysonと通信を行ってみます MQTTは様々な言語でライブラリが用意されているので、好きな言語で触れると思います 自分は自宅IoTをpythonで書いているので、今回はpythonで行います

  • MQTTインストール
  • pip install paho-mqtt

センサーの値を取得

topicを特定

MQTTの仕様上 dyson側から送られてくる値を取得するにはtopicという識別子が必要になります 先ほど同様にwiresharkのパケットを見てdyson側からpublish messageされているパケットを探します

f:id:AAkira:20160811225410p:plain

topicありましたね
どうやら、このtopicでセンサーの値が送られくるようです

subscriber script

# coding: UTF-8

import paho.mqtt.client as mqtt

HOST = 'your ip address'
PORT = 1883
USERNAME = 'your user name'
PASSWORD = 'your password'
topic = '475/' + USERNAME + '/status/current'  # 475はおそらくdyson pure cool link(でかい方のみ?)の識別子です。使用している製品で各自入力して下さい

def on_connect(client, userdata, flags, respons_code):
    print('status : ' + str(respons_code))
    client.subscribe(topic)

def on_message(client, userdata, msg):
    print('-----' + msg.topic + '-----')
    print(msg.payload)

if __name__ == '__main__':
    client = mqtt.Client(protocol=mqtt.MQTTv311)
    client.username_pw_set(USERNAME, PASSWORD)
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect(HOST, port=PORT, keepalive=60)
    client.loop_forever()

このスクリプトを実行して、付属の物理リモコンでdysonを操作してみると以下のJSONが返ってきました!!

{"msg":"STATE-CHANGE","time":"2016-08-11T13:46:27.000Z","mode-reason":"PRC","state-reason":"MODE","product-state":{"fmod":["FAN","FAN"],"fnst":["FAN","FAN"],"fnsp":["0007","0008"],"qtar":["0003","0003"],"oson":["OFF","OFF"],"rhtm":["OFF","OFF"],"filf":["4291","4291"],"ercd":["NONE","NONE"],"nmod":["OFF","OFF"],"wacd":["NONE","NONE"]},"scheduler":{"srsc":"0000","dstv":"0000","tzid":"0000"}}

2つの配列になっているのは、前回の値と今回変化した値が入っています
今回の場合はfnsp ファンスピードが 7 -> 8 になった時に送られた値です。
他にもあるのですが、全部は把握出来なかったので一部意味を載せます

name 意味
fmod モード (FAN, AUTO)
fnsp ファンスピード(0001 - 0010)
oson 首振り(ON, OFF)
nmod ナイトモード(ON, OFF)

他にも定期的に現在のセンサーデータがpublishされています

{"msg":"ENVIRONMENTAL-CURRENT-SENSOR-DATA","time":"2016-08-11T09:44:32.004Z","data":{"tact":"3034","hact":"0053","pact":"0002","vact":"0000","sltm":"OFF"}}

自宅をIoTしてる人はこのセンサーデーターを定期的にDBに保存しておけば、特定の温度でエアコン起動してslackに通知等いろいろ面白い事が出来そうです(・∀・)

name 意味
tact 温度 -> 摂氏変換 x / 10.0 - 273 (3034 / 10.0 - 273 = 30℃)
hact 湿度 (%)

扇風機の操作

操作に関してもMQTTを使用します

publisher script

import paho.mqtt.client as mqtt

HOST = 'your ip address'
PORT = 1883
USERNAME = 'your user name'
PASSWORD = 'your password'
topic = '475/' + USERNAME + '/command'

PAYLOAD = '{"msg":"STATE-SET","time":"2016-08-11T14:57:17Z","data":{"oson":"OFF","fnsp":"0009","nmod":"OFF","fmod":"FAN"}}'

if __name__ == '__main__':
    client = mqtt.Client(protocol=mqtt.MQTTv311)
    client.username_pw_set(USERNAME, PASSWORD)
    client.connect(HOST, port=PORT, keepalive=60)
    client.publish(TOPIC, PAYLOAD)
    client.disconnect()

基本はpayloadの部分を変更するだけで動作します。
ただ、複数の状態変更は同時に受け付けない仕様みたいなので、複数同時に送る場合は現在の値と整合性をとってから送る必要があるので、 基本的に dataの中身は1つだけ送った方が良さそうです。 "data":{"fnsp":0010"} とか timeパラメータは無いと動作しなかったのですが、中身の時間は適当でも動きました。

付録(識別子一覧)

payloadに来るmsgにもいくつか種類があり、他には以下のメッセージがあるみたいです topicも複数あるみたいですが、全てdyson pure cool linkで使われるのかはわかりません
他のdyson製品hot & cool, 360eye等で使用するものもあるみたいです

受信message一覧

name
HELLO
CURRENT-STATE
STATE-CHANGE
ENVIRONMENTAL-CURRENT-SENSOR-DATA
GOODBYE
FAULTS-CHANGE
CURRENT-FAULTS

topic一覧

name
/status/current
/status/faults
/status/connection
/status/software
/status/summary

まとめ

今回はdyson pure cool linkのhackにチャレンジしました。
基本操作、センサーの値取得両方とも実現出来てとても満足してます!
自宅の家電は全てRaspberry Piから操作出来るようになっているのですが、
今回のようにAPIが公開されていない端末だと一括管理が出来ずに困ります。
高級扇風機とあって値段はお世辞にも安いとは言えませんが、 こんな風にいろいろ遊べるなら安く感じてきませんか?w
いつか公式APIが出ると良いですね!
良いIoT LIFEを!!

dyson pure cool linkを買いました

       f:id:AAkira:20160811184519j:plain

 

一人暮らしをしていると、収納のスペースが限られるので季節家電を買うのは気が引けます。
パット思いつくのは、扇風機とこたつでしょうか?
こたつは個人的に不要なのですが、エアコンがあまり好きではないので扇風機は必須家電です。

ただ従来の扇風機は収納に場所をとります、かと言って一年中置いておくのは気が引けます。
そこで、羽なし扇風機でおなじみdysonの扇風機を購入しました。

 

                       f:id:AAkira:20160811184720p:plain 

dysonの扇風機は2016年モデルからIoTに対応し、
android, iPhoneアプリから操作することが可能です。

このように部屋の空気を監視していて、自宅の場所を登録すると外気との差を表示してくれます。

 

  f:id:AAkira:20160811184755p:plain  f:id:AAkira:20160811184744p:plain

コントローラーとしても使えたり、

まだデータがありませんが毎日の空気のログをとってくれます。

 

風量も申し分なく、白の流線型でスタイリッシュなフォルムが美しいです。

扇風機として見ると正直高いですが、空気清浄機とその他IoT機能を付加価値としてみると、ギリ許せる範囲なのではないかと思います。

 

IoTを利用したい場合は2016年度モデルからなので製品名にlinkが付いている事を確認してください。

他にもデスクに置くのに調度良い少し小さめなテーブルファンもあります。