Created
August 27, 2017 20:12
-
-
Save rringler/35ffa241b4d7a8a2e08dde7543fae55c to your computer and use it in GitHub Desktop.
Shell Script to control a TP-Link HS100 Smart Outlet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
## | |
# Controls TP-LINK HS100,HS110, HS200 wlan smart plugs | |
# Tested with HS100 firmware 1.0.8 | |
# | |
# Credits to Thomas Baust for the query/status/emeter commands | |
# | |
# Author George Georgovassilis, https://github.com/ggeorgovassilis/linuxscripts | |
ip=$1 | |
port=$2 | |
cmd=$3 | |
# encoded (the reverse of decode) commands to send to the plug | |
# encoded {"system":{"set_relay_state":{"state":1}}} | |
payload_on="AAAAKtDygfiL/5r31e+UtsWg1Iv5nPCR6LfEsNGlwOLYo4HyhueT9tTu36Lfog==" | |
# encoded {"system":{"set_relay_state":{"state":0}}} | |
payload_off="AAAAKtDygfiL/5r31e+UtsWg1Iv5nPCR6LfEsNGlwOLYo4HyhueT9tTu3qPeow==" | |
# encoded { "system":{ "get_sysinfo":null } } | |
payload_query="AAAAI9Dw0qHYq9+61/XPtJS20bTAn+yV5o/hh+jK8J7rh+vLtpbr" | |
# the encoded request { "emeter":{ "get_realtime":null } } | |
payload_emeter="AAAAJNDw0rfav8uu3P7Ev5+92r/LlOaD4o76k/6buYPtmPSYuMXlmA==" | |
# tools | |
check_dependencies() { | |
command -v nc >/dev/null 2>&1 || { echo >&2 "The nc programme for sending data over the network isn't in the path, communication with the plug will fail"; exit 2; } | |
command -v base64 >/dev/null 2>&1 || { echo >&2 "The base64 programme for decoding base64 encoded strings isn't in the path, decoding of payloads will fail"; exit 2; } | |
command -v od >/dev/null 2>&1 || { echo >&2 "The od programme for converting binary data to numbers isn't in the path, the status and emeter commands will fail";} | |
command -v read >/dev/null 2>&1 || { echo >&2 "The read programme for splitting text into tokens isn't in the path, the status and emeter commands will fail";} | |
command -v printf >/dev/null 2>&1 || { echo >&2 "The printf programme for converting numbers into binary isn't in the path, the status and emeter commands will fail";} | |
} | |
show_usage() { | |
echo Usage: $0 IP PORT COMMAND | |
echo where COMMAND is one of on/off/check/status/emeter/toggle | |
exit 1 | |
} | |
check_arguments() { | |
check_arg() { | |
name="$1" | |
value="$2" | |
if [ -z "$value" ]; then | |
echo "missing argument $name" | |
show_usage | |
fi | |
} | |
check_arg "ip" $ip | |
check_arg "port" $port | |
check_arg "command" $cmd | |
} | |
send_to_plug() { | |
ip="$1" | |
port="$2" | |
payload="$3" | |
echo -n "$payload" | base64 --decode | nc -v $ip $port || echo couldn''t connect to $ip:$port, nc failed with exit code $? | |
} | |
decode(){ | |
code=171 | |
offset=4 | |
input_num=`od -j $offset -An -t u1 -v | tr "\n" " "` | |
IFS=' ' read -r -a array <<< "$input_num" | |
args_for_printf="" | |
for element in "${array[@]}" | |
do | |
output=$(( $element ^ $code )) | |
args_for_printf="$args_for_printf\x$(printf %x $output)" | |
code=$element | |
done | |
printf "$args_for_printf" | |
} | |
query_plug(){ | |
payload=$1 | |
send_to_plug $ip $port "$payload" | decode | |
} | |
# plug commands | |
cmd_print_plug_relay_state(){ | |
output=`send_to_plug $ip $port "$payload_query" | decode | egrep -o 'relay_state":[0,1]' | egrep -o '[0,1]'` | |
if [[ $output -eq 0 ]]; then | |
echo OFF | |
elif [[ $output -eq 1 ]]; then | |
echo ON | |
else | |
echo Couldn''t understand plug response $output | |
fi | |
} | |
cmd_print_plug_status(){ | |
query_plug "$payload_query" | |
} | |
cmd_print_plug_consumption(){ | |
query_plug "$payload_emeter" | |
} | |
cmd_switch_on(){ | |
send_to_plug $ip $port $payload_on > /dev/null | |
} | |
cmd_switch_off(){ | |
send_to_plug $ip $port $payload_off > /dev/null | |
} | |
cmd_switch_toggle() { | |
output=`cmd_print_plug_relay_state` | |
if [[ $output == OFF ]]; then | |
cmd_switch_on | |
elif [[ $output == ON ]]; then | |
cmd_switch_off | |
else | |
echo $output | |
fi | |
} | |
## | |
# Main programme | |
## | |
check_dependencies | |
check_arguments | |
case "$cmd" in | |
on) | |
cmd_switch_on | |
;; | |
off) | |
cmd_switch_off | |
;; | |
toggle) | |
cmd_switch_toggle | |
;; | |
check) | |
cmd_print_plug_relay_state | |
;; | |
status) | |
cmd_print_plug_status | |
;; | |
emeter) | |
cmd_print_plug_consumption | |
;; | |
*) | |
show_usage | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment