0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

tp-link HS105によるTV強制オフ

Last updated at Posted at 2021-04-17

Motivation

子供が無制限にTVを見てしまうので、見たいTV番組以外は自動でTVへの給電ON/OFFを行うため、tp-linkのHS105というのを買ってみた。iPhoneからスケジュール設定できる。
https://www.tp-link.com/jp/home-networking/smart-plug/hs105/

スケジュールした時間に給電OFFになっても横のボタンで物理的にONできるので、ボタン押したらTV点くことを子供が覚えてしまった。厚紙で蓋をしたけど、無理やり押す。。。
IMG_0908.jpg
埃汚くてすいません。。。

やったこと

HS105にはAPIがあって、その制御スクリプトが公開されているので、HS105のボタンを押そうがcronで30秒以内に給電OFFにするよう改変した(以下diff参照)。。。
(1年前にやったので下記版を改変)
https://github.com/softScheck/tplink-smartplug/blob/a094843c64bbfe62780f0e74412c090ad15a9f6d/tplink_smartplug.py

1c1
< #!/usr/bin/env python2
---
> #!/usr/bin/python
25a26,29
> import json
> import datetime
> import time
> 
72,86d75
< # Parse commandline arguments
< parser = argparse.ArgumentParser(description="TP-Link Wi-Fi Smart Plug Client v" + str(version))
< parser.add_argument("-t", "--target", metavar="<hostname>", required=True, help="Target hostname or IP address", type=validHostname)
< group = parser.add_mutually_exclusive_group(required=True)
< group.add_argument("-c", "--command", metavar="<command>", help="Preset command to send. Choices are: "+", ".join(commands), choices=commands)
< group.add_argument("-j", "--json", metavar="<JSON string>", help="Full JSON string of command to send")
< parser.add_argument('--influxdb', type=str, metavar=("URI", "database"), default=None,
< 		nargs=2, help='If command is "energy", push to influxdb. URI should point to influxdb, e.g. [http/https]://<ip>:<port>. Database: e.g. smarthome.')
< parser.add_argument('--influxdb_energy', type=str, metavar="query", default=None,
< 		help='query to store energy as Joule, e.g. energy,type=elec,device=hs110-1 this will be appended with <energy in joule> (as int)')
< parser.add_argument('--influxdb_power', type=str, metavar="query", default=None,
< 		help='query to store power as Watt, e.g. power,type=elec,device=hs110-1 this will be appended with <power in W> (as float)')
< args = parser.parse_args()
< 
< 
88c77
< ip = args.target
---
> ip = '192.168.0.7'
90,95c79,80
< if args.command is None:
< 	cmd = args.json
< else:
< 	cmd = commands[args.command]
< 
< 
---
> cmd = '{"system":{"get_sysinfo":{}}}'
> cmd2 = '{"system":{"set_relay_state":{"state":0}}}'
97a83
> while True:
98a85,88
>                 dt_now = datetime.datetime.now()
>                 print dt_now
>                 if dt_now.hour >= 21:
>                         break
105,112c95,105
< 	print "Sent:     ", cmd
< 	print "Received: ", decrypt(data[4:])
< except socket.error:
< 	quit("Cound not connect to host " + ip + ":" + str(port))
< 
< if (args.command == "energy") and (args.influxdb != None):
< 	import requests
< 	import json
---
>                 json_dict = json.loads(decrypt(data[4:]))
>                 relay_state = json_dict['system']['get_sysinfo']['relay_state']
>                 print "relay_state:     ", relay_state
>                 if relay_state == 1:
>                         sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>                         sock_tcp.connect((ip, port))
>                         sock_tcp.send(encrypt(cmd2))
>                         data = sock_tcp.recv(2048)
>                         sock_tcp.close()
>                 time.sleep(30)
114,129c107
< 	# Get total_wh and power_mw from json response
< 	energy_response = decrypt(data[4:])
< 	energy_wh = json.loads(energy_response)['emeter']['get_realtime']['total_wh']
< 	energy_joule = int(energy_wh)*3600
< 	power_mW = json.loads(energy_response)['emeter']['get_realtime']['power_mw']
< 	power_W = float(power_mW)/1000.0
< 
< 	# Build URI and query
< 	# Something like req_url = "http://localhost:8086/write?db=smarthometest&precision=s"
< 	# Something like post_data = "water,type=usage,device=devicename value=1"
< 	req_url = args.influxdb[0]+"/write?db="+args.influxdb[1]+"&precision=s"
< 	post_data = ""
< 	if (args.influxdb_energy != None):
< 		post_data = args.influxdb_energy+" value="+str(energy_joule)
< 	if (args.influxdb_power != None):
< 		post_data += "\n"+args.influxdb_power+" value="+str(power_W)
---
> #00 19 * * 1 /home/pi/my_tplink_smartplug.py >> /var/log/tplink.log 2>&1
131,137c109,110
< 	# Post data to influxdb, check for obvious errors
< 	try:
< 		httpresponse = requests.post(req_url, data=post_data, verify=False, timeout=5)
< 		if (httpresponse.status_code != 204):
< 			print "Push to influxdb failed: " + str(httpresponse.status_code) + " - " + str(httpresponse.text)
< 	except requests.exceptions.Timeout as e:
< 		print "Update failed due to timeout. Is influxdb running?"
---
>         except socket.error:
>                 quit("Cound not connect to host " + ip + ":" + str(port))

95-105行目あたりで cmd = '{"system":{"get_sysinfo":{}}}' で給電ON/OFFステータスrelay_stateを取得して、ON: 1にされてたら cmd2 = '{"system":{"set_relay_state":{"state":0}}}' でOFFにするだけ。
87行目あたりで21時まで有無を言わさず無限ループ

cron設定

常時動いているraspberry piにTV番組終了に合わせてcronでスクリプト起動。さて何のTV見てるでしょう?

32 18 * * 1 /home/pi/my_tplink_smartplug.py > /var/log/tplink.log 2>&1
17 19 * * 2 /home/pi/my_tplink_smartplug.py > /var/log/tplink.log 2>&1
32 18 * * 3 /home/pi/my_tplink_smartplug.py > /var/log/tplink.log 2>&1
17 19 * * 4 /home/pi/my_tplink_smartplug.py > /var/log/tplink.log 2>&1
57 19 * * 5 /home/pi/my_tplink_smartplug.py > /var/log/tplink.log 2>&1

仕事中にTVが消えたとメールで連絡が来るが、外からは家に入れないので、家に帰らないと無理と言って、諦めてもらう。。。

余談

本題とは関係ありませんが、下記を参照してDynamic DNSを使って外からSSHで家に入れるようにした。
送信元アドレス制限しないと、22番ポートにメッチャ不正アクセス来ます。

AWSのRoute 53でドメインホストしているので、下記のようなスクリプトをclonで定期的に動かして、内部サーバにポートフォワードかけてるHGWのグローバルアドレスのAレコードを更新
ip.txtに前回のアドレスを書いておいて、変わってたらaws-cliで更新

updatedns.sh
# !/bin/sh
NEWIP=`/usr/bin/curl -s https://api.ipify.org`
IP=`cat /home/pi/ip.txt`
if [ -n $NEWIP ] && [ $IP != $NEWIP ]; then
    cp /home/pi/template.json /home/pi/current.json
    sed -i 's/<IP>/'"$NEWIP"'/' /home/pi/current.json
    echo $NEWIP > /home/pi/ip.txt
    /usr/bin/aws --debug --output=table route53 change-resource-record-sets --hosted-zone-id ドメインのzone id(ドメイン名ではない) --change-batch file:///home/pi/current.json
fi

更新のDNSレコード更新のtemplateはこんな感じ

template.json
{
  "Comment": "Update by updatedns.sh",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "ホスト名",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [
          {
            "Value": "<IP>"
          }
        ]
      }
    }
  ]
}

AWSのIAMはPoliciesからAmazonRoute53FullAccessをユーザに足しとく。
Screen Shot 2021-04-18 at 19.27.55.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?