TP-LINK WiFiスマートプラグをESP32(Arduino)から制御する

家電の電源制御のために市販の赤外線リモコン・コンセントに自作の赤外線リモコン送信機を組み合わせて使っていたが、2つのHWの設置場所の制約に加えコンセントも余計に占有してしまうため、なんとかならんもんかなと常々思っていたところ、な~んと、TP-LINKのスマートプラグ(HS100/105/110)のプロトコルを解析してしまった猛者がいるのを発見してしまった。世の中には凄い人がいるもんだ。(/・ω・)/

Reverse Engineering the TP-Link HS110

早速、その内容を元に試して見た所、WiFiスマートプラグ(HS105)をESP32(Arduino)から制御することに見事に成功。(/・ω・)/

TPLinkSmartPlugクラスは家電制御向けに有用と思われる機能をESP32に依存しないよう汎用的な実装を心がけたつもりなのでTCPが使える全てのArduinoで使えるはず。試してないけど...

未実装な機能は沢山あるが使うのが面倒な機能や管理系機能が多いので初期設定やその他の機能についてはKasaアプリを利用するのが良いだろう。ちなみにローカルLAN上で直接スマートプラグと通信するためKasaのクラウド・アカウントは必要ない。それと、スマートプラグのプロトコル仕様が変更されたりすると動作しなくなる可能性が考えられるので気になる人はファームウェア更新はしないほうが良いとは思うが、仕様変更などしたら稼働中の全世界中のTP-LINKスマートホーム・デバイスが一斉に動作しなくなるという大問題が発生するためそう気にする必要もないだろう。

昨今、IoTと呼ばれる様々な手法があるが家電制御するためになんでもかんでもインターネットに繋ぐというのはセキュリティ的に問題があるばかりでなく動作遅延や故障率的にも問題がありすぎると言わざる得ない。家の中と外のネットワークは明確にわけて必要な機能のみ部分的に連携するべきと思うがそんなことを考えるのは私だけだろうか...

【約1秒毎にオンオフを切り替えるサンプルスケッチ】

【修正履歴】
2018-09-03
複数端末へアクセスする場合、途中で動作を停止した端末があったりすると、その後、アクセス毎に即時的discoveryを実行し無駄に時間を消費してしまうため、即時的discoveryは最初の一回のみに制限してみた。
★ちなみに原因不明の動作遅延についてはESP32が原因だった...PCから操作してみたところ全く問題なし。ESP8266のようにESP32も通信処理の遅延がそれなりに起こるようだ。このCPUは何をするにも簡単なんだけど、品質的、電気的、ソフトウェア的に洗練しきれていないように感じる。なので実験用としてはいいかもしれないが実用には使いものにならない。我が家でも一時は8個ぐらい常時稼働してみたことがあったが2年も経過しないうちに3個も壊れてしまったので運用的に問題なさそうな2個を残し全て他のCPUに入れ替えている。個人的な所感ではあるがこのCPUで実用システムを組むことはお勧めできない。と思う。

2018-09-02
複数端末が存在する場合、一回のDiscovery処理では端末の見落としが発生しやすいことがわかりポーリング方式に変更。さらに一定時間間隔(60秒)毎にDiscoveryを繰り返すように変更。追加関数は下記の通り。
下記のどちらかををloop()内で呼び出さなければならない。
handle()
delay(uint32_t ms)
ついでに端末名のほかにMACアドレスでも発見できるように改良。

2018-09-01
ArduinoのEthernetクラスにも対応できるようコンストラクタで指定していた引数をbegin()で指定するように変更。それにともないbegin()で指定した引数は新たなsetTarget()により指定するように変更。
それと、より確実なDiscoveryのためにロジックを若干修正。

2018-08-31
端末を発見できない可能性があったので確実に発見できるように改良。

2018-08-30
TP-Link Smart plug Discovery Protocol に対応し、Kasaアプリの初期設定にて設定した端末名をbegin()にて指定出来るようにした。これに伴い同じ名前を持つ全ての端末を同時制御する仕様に変更。

2018-08-25
TCPクライアント指定をコンストラクタで指定できるように変更。スマートプラグのアドレス指定にIPAdressを使っていたが、より柔軟性のある文字列指定に変更。バイトオーダー変更のためのhtonl()/ntohl()が存在しないボード環境があったので自前の関数に置き換え。同じくvsprintf()が存在しないボード環境があったのでsnprintf()へ変更。
あと、失敗するわけではないが、時々、送信に時間がかかることがあるので試しに受信ループにdelay(1)を入れてみたが状況変わらず。失敗しないということはスマートプラグの反応が遅いだけかな?

【ライブラリの概要説明】

【サンプル・スケッチ】

【ライブラリ】