電源の自動On/Off
https://scrapbox.io/files/617e5a222bb379001d27b438.png
スマートプラグを使い、電源のOn/Offを自動化する
スマートプラグ is 何
こんなん
https://scrapbox.io/files/617e5bac39268900226f3a01.jpg
これを「コンセントや電源タップ」と「電子機器のプラグ」の間に挟むように設置することで電源のOn/Offを遠隔操作できる
なぜスマートプラグなのか
従来はアクアリウム用照明などの各製品の機能としてタイマーが備わっていたり専用アプリで管理できたりしていたが、当然ながら外部のコンピュータからの制御などはできず、出来ることにも限りがある
スマートプラグであれば任意の電子機器を接続してLAN経由でRaspberry Piから遠隔制御できるため汎用性がある
要件
スマートプラグに接続した機器の電源を遠隔でOn/Offできる
仕様
仕様1:Raspberry Piからプログラムを実行すると、スマートプラグに接続した機器の電源がOnまたはOffに切り替わる
使用したもの
あしゅりーアクアリウムの場合
table:使用したもの
ラズパイ Raspberry Pi 4 ModelB 4GB
スマートプラグ TP-Link HS105
テスト用電子機器 (ex.)アクアリウム用照明
スマートプラグ:TP-Link HS105
上記の写真がHS105
あしゅりーアクアリウムでは複数の電子機器をこれで制御しているので、同じようにやる場合は複数個買っておくと良い
電源のOn/Offは以下の4つの手段がある
HS105の筐体にある物理ボタンの押下
TP-Link製品共通の専用アプリ「Kasa Smart」から操作
オープンソースのNode.js用ライブラリ「tplink-smarthome-api」による制御
本当は↑でやろうとしたがPythonでソケット通信による制御ができるっぽいので今回はこれ
注意:HS105のプラグ側はN極プラグ(刃の片方が大きい)になっており、N極に対応していないコンセントや電源タップには刺さらないのでN極対応タップなどを用意しておく
HS105のソケット側(任意の電子機器接続側)もN極対応の形状となっているが、こちらは極性無しプラグ(両刃が同じ大きさ)も使えるので特に気にする必要は無し
設計
全面的に以下を参考にした
上記にて、Node.jsではなくPythonでの制御を行った(記事内①と③を行った)
流れは以下の通り
「Kasa Smart」でHS105をLANに参加させる
「tplink-smarthome-api」でHS105のIPアドレスを特定
ソケット通信によりHS105のOn/Offを切り替えるプログラムを作成
「Kasa Smart」でHS105をLANに参加させる
ラズパイからHS105を制御するためにはまずHS105をラズパイが属するLANに参加させておく必要がある
TP-Link製品共通の専用アプリ「Kasa Smart」でこれが行える
iOS/Androidの上記アプリをダウンロード
マニュアル等を適宜参考の上、アプリにてHS105をLANに参加させる
アプリ上の操作でHS105の電源をOn/OffできればOK
HS105にテスト用の電子機器をつないでOn/Offしてみる
「tplink-smarthome-api」でHS105のIPアドレスを特定
次にLANに参加させたHS105をラズパイから制御するため、HS105のIPアドレスを確認する
「tplink-smarthome-api」をインストール
code:Terminal
$ sudo npm install -g tplink-smarthome-api
以下のコマンドでLANに接続されているTP-Link製品を検索する
code:Terminal
$ tplink-smarthome-api search
HS105が正しく接続されていれば以下のような結果が返ってくる
code:Terminal
HS105(JP) plug IOT.SMARTPLUGSWITCH 192.168.1.101 9999 ...
上記の例では「192.168.1.101」がLANによって振られたHS105のIPアドレスとなる
上手く結果が返ってこない場合、ファイヤウォール設定などを一時的に無効化することで改善する可能性がある
あしゅりー.iconはufwをenableとしていたことで上手くHS105を検出できず、これを一時的にdisableして再度検索すると上手く検出できた
ソケット通信によりHS105のOn/Offを切り替えるプログラムを作成
参考にした下記記事のコードをもとに必要な部分だけを抽出して使用した
詳細は記事を参照のこと
指定したIPアドレスのHS105について電源のOn/Offを切り替えるプログラムを以下の通り作成した
code:control_plug.py
import sys
import socket
from struct import pack
import re
class TpPlug():
def __init__(self, ip, port=9999):
self.__ip = ip
self.__port = port
def info(self):
cmd = '{"system":{"get_sysinfo":{}}}'
receive = self.send_command(cmd)
return receive
def on(self):
cmd = '{"system":{"set_relay_state":{"state":1}}}'
receive = self.send_command(cmd)
def off(self):
cmd = '{"system":{"set_relay_state":{"state":0}}}'
receive = self.send_command(cmd)
def check_plug_state(self):
receive = self.info()
if re.search(r',"relay_state":1,', receive):
return 'on'
elif re.search(r',"relay_state":0,', receive):
return 'off'
else:
return 'error'
def send_command(self, cmd, timeout=10):
try:
sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.settimeout(timeout)
sock_tcp.connect((self.__ip, self.__port))
sock_tcp.settimeout(None)
sock_tcp.send(self.encrypt(cmd))
data = sock_tcp.recv(2048)
sock_tcp.close()
decrypted = self.decrypt(data4:) return decrypted
except socket.error:
quit("Could not connect to host " + self.__ip + ":" + str(self.__port))
return None
def encrypt(self, string):
key = 171
result = pack('>I', len(string))
for i in string:
a = key ^ ord(i)
key = a
return result
def decrypt(self, string):
key = 171
result = ""
for i in string:
a = key ^ i
key = i
result += chr(a)
return result
def plug_status(plug):
tp = TpPlug(plug)
now_state = tp.check_plug_state()
return now_state
def plug_on(plug):
tp = TpPlug(plug)
now_state = tp.check_plug_state()
if now_state == 'on':
return 'already'
elif now_state == 'off':
tp.on()
if tp.check_plug_state() == 'on':
return 'success'
else:
return 'fail'
else:
return 'error'
def plug_off(plug):
tp = TpPlug(plug)
now_state = tp.check_plug_state()
if now_state == 'off':
return 'already'
elif now_state == 'on':
tp.off()
if tp.check_plug_state() == 'off':
return 'success'
else:
return 'fail'
else:
return 'error'
if __name__ == '__main__':
PLUG = '192.168.1.101'
args = sys.argv
if(len(args) > 1):
plug_on(PLUG)
plug_off(PLUG)
else:
pass
PLUGに特定したHS105のIPアドレスを指定する
HS105の電源をOnにしたい場合
code:Terminal
$ python3 control_plug.py on
HS105の電源をOffにしたい場合
code:Terminal
$ python3 control_plug.py off
上記にてHS105のOn/Offが切り替わり、接続している電子機器もOn/Offできるていることを確認する
当然ながら、接続している電子機器自身の電源ボタンはOnにしておく
完了 ⇒ 仕様1:Raspberry Piからプログラムを実行すると、スマートプラグに接続した機器の電源がOnまたはOffに切り替わる
注意点
スマートプラグのIPアドレスはそれが属するLANのルータによって割り当てられているため、ルータを再起動などした場合に別のIPアドレスに変わってしまうことがあり、以後スマートプラグを制御できなくなってしまう
そのため、多くのルータに搭載されているIPアドレスの固定機能を利用して、アドレスが変わらないように設定しておくと良い
活用
システム構成図
「Smart plugs」が実現できたことになる
システム構成図.icon