TP-LINK HS100 Smart Plug (WiFi)?

Tags: #<Tag:0x00007f6173e85180> #<Tag:0x00007f6173e85090> #<Tag:0x00007f6173e84f78>

Does anybody ever tried the TP-LINK HS100 Smart Plug ?

http://www.tp-link.com/en/products/details/cat-5258_HS100.html

It’s a wifi-based product, seemengly compatible with Amazon Echo. It would be interesting to see it controlled in openHAB …

Riccardo

Don’t know about the TP-Link, but I use the Kan Kun smart plug for WiFi enabled outlets and then use the Echo GA bridge.

There is an active Google + group for the Kan Kun to get into it enable an http interface.

The TP-LINK HS110 (with energy monitor) is on sale, 2 for $35.

The D-Link ones are also on sale, 4 for $60 (no energy monitoring)

Would be awesome if OpenHAB can control these.

The D-Link one looks promising considering that it was some known vulnerabilities in the past that allow you get console access. If that still works then, OpenHAB can control it by SSH/Telnet if nothing else.

I recently purchased one of these HS100 plugs thinking I could make it work with openHAB, only to find there’s not a Binding. I was a bit bummed. I’ve been doing some reading and it appears TP-Link is rather open with parts of their software. http://www.tp-link.com/en/gpl-code.html Further more like the Kan Kun mentioned earlier in the post the HS100 appears to run on some version of Linux. I only recently jumped off the deep end into Linux and don’t yet have enough understanding on how to actually make this stuff work. Alternatly I attempted a work around solution using IFTTT, but there were no channels created for the TP-Link app Kasa. After finally getting the OpenHAB system set-up this was my first step in home automation and it was an epic compatibility failure. is there anybody out there that has made progress integrating this device?

Try this with exec binding

https://github.com/ggeorgovassilis/linuxscripts/blob/master/tp-link-hs100-smartplug/switch-plug.sh

Thank you very much for your help. It took some time for me to understand the script you posted and then learn how to use the exec binding. In the end I was successful. In addition to this script one also needs the protocol for executing the script which was in a readme file inside ggeorgovassilis post.
switch-plug.sh 192.168.1.20 9999 on
Second I ended up using this post almost exclusively to understand the useage of the exec binding.

Thank you again.

2 Likes

You guys are awesome! I got mine to turn on/off using this. Just curious – how does one intercept and reverse engineer the binary payload?

Edit: Found it: Here’s the original post and an enhanced script: https://georgovassilis.blogspot.com/2016/05/controlling-tp-link-hs100-wi-fi-smart.html

1 Like

Best give a check at this reverse engineering stuff:

No more encrypted payload and a lot more possibilities

Got simple on/off action within an OpenHAB rule using executeCommandLine() as in

executeCommandLine("/usr/bin/python /opt/openhab/configurations/scripts/tplink-smartplug.py -t 192.168.2.195 -c on")

I have a bit of history reverse engineering protocols, and found this one to be fun and only a little tricky. I have yet to capture the initial config commands as it’s harder to do a MITM monitoring (but I’ll get that done eventually)

I have never written an OpenHAB binding, yet this may be a good one to work on.

These devices speak JSON. For instance, "AAAAKtDygfiL/5r31e+UtsWg1Iv5nPCR6LfEsNGlwOLYo4HyhueT9tTu36Lfog==" is a length-prefix encoded sort of encrypted string for: {"system":{"set_relay_state":{"state":1}}}

There is also a sort of discovery one can do to learn what the device is. For instance, sending {"system":{"get_sysinfo":null}} (which the app sends) to one of my bulbs, results in:

{
  "system": {
    "get_sysinfo": {
      "sw_ver": "1.1.2 Build 160927 Rel.111100",
      "hw_ver": "1.0",
      "model": "LB130(US)",
      "description": "Smart Wi-Fi LED Bulb with Color Changing",
      "alias": "rgb-bulb-02",
      "mic_type": "IOT.SMARTBULB",
      "dev_state": "normal",
      "mic_mac": "<redacted>",
      "deviceId": "<redacted>",
      "oemId": "<redacted>",
      "hwId": "<redacted>",
      "is_factory": false,
      "disco_ver": "1.0",
      "ctrl_protocols": {
        "name": "Linkie",
        "version": "1.0"
      },
      "light_state": {
        "on_off": 0,
        "dft_on_state": {
          "mode": "normal",
          "hue": 0,
          "saturation": 0,
          "color_temp": 6500,
          "brightness": 100
        }
      },
      "is_dimmable": 1,
      "is_color": 1,
      "is_variable_color_temp": 1,
      "preferred_state": [
        {
          "index": 0,
          "hue": 0,
          "saturation": 0,
          "color_temp": 2700,
          "brightness": 50
        },
        {
          "index": 1,
          "hue": 0,
          "saturation": 75,
          "color_temp": 0,
          "brightness": 100
        },
        {
          "index": 2,
          "hue": 120,
          "saturation": 75,
          "color_temp": 0,
          "brightness": 100
        },
        {
          "index": 3,
          "hue": 240,
          "saturation": 75,
          "color_temp": 0,
          "brightness": 100
        }
      ],
      "rssi": -64,
      "active_mode": "none",
      "heapsize": 363984,
      "err_code": 0
    }
  }
}

Note this control protocol is completely insecure. Anyone who can talk to your devices can reconfigure them, including taking control of them, uploading malicious firmware, and perhaps gaining access to a shell (they run Linux).

For my setup, all the bulbs are on a WiFi SSID dedicated to just home automation, and this maps to a VLAN that has no internet access, and indeed cannot initiate an outgoing connection. This means the cloud component of the system is dead – which is fine by me! I may have to end up allowing it to perform firmware upgrades, if they ever have one.

Note also that even though my bulbs live in their own little world, they do not only accept connections on port 9999 from things on their local network, but from anywhere that can reach that port. In my case, this is an OpenHAB box on a different VLAN/subnet, which is good. This means I don’t have to put the OpenHAB server on what I consider to be a very insecure network.

Eventually, a full-blown binding would be neat for this. Seems like an easy enough project (maybe I’ll take a stab, just to get familiar with binding development).

In case anyone wants an auto-updating Switch in OH2 that works with this in the meantime:
https://community.openhab.org/t/oh2-switch-triggered-rule-not-working/

My primary motivation was wanting OH-backed UIs to properly show the outlet state when it gets changed from somewhere else (such as Alexa).

I have a Ruby script that polls the network for all of the tp-link bulbs and outlets I have, and sends this on an mqtt topic. The same Ruby script remembers where these devices live in IP address space, and also accepts commands to turn them on and off.

I think it’s time to open source my minor amount of work…

1 Like

The commands for the smart bulbs are like this

I figured these out myself and tested them and they work.

{“smartlife.iot.smartbulb.lightingservice”:{“transition_light_state”:{“ignore_default”:0,“mode”:“normal”,“on_off”:0,“transition_period”:0}}}
{“smartlife.iot.smartbulb.lightingservice”:{“transition_light_state”:{“ignore_default”:0,“mode”:“normal”,“on_off”:1,“transition_period”:0}}}

there are several other commands for “brightness”, etc

Yes! I am trying to use a javascript lib for the plugs to decode the bulbs and having some issues. Any hints on decoding the bulb’s messages would be greatly appreciated.

What is the algorithm you are using to decode? I am using this (in javascript, from this node lib) and getting gibberish mixed with bits of JSON:

function decrypt(input, firstKey) {
  if (typeof firstKey === 'undefined') firstKey = 0x2B;
  var buf = new Buffer(input); // node v6: Buffer.from(input)
  var key = firstKey;
  var nextKey;
  for (var i = 0; i < buf.length; i++) {
    nextKey = buf[i];
    buf[i] = buf[i] ^ key;
    key = nextKey;
  }
  return buf;
}

here is shell script that controls tplink

#!/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 $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
;;
on)
cmd_switch_on
;;
OFF)
cmd_switch_off
;;
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

use it as:
/opt/openhab2/conf/scripts/hs100.sh 192.168.10.42 9999 OFF
/opt/openhab2/conf/scripts/hs100.sh 192.168.10.42 9999 on
/opt/openhab2/conf/scripts/hs100.sh 192.168.10.42 9999 status
i do not know how to attach to the message - it screwed script a bit replacing # characters with bigger font encodings.

Are there commands that allow you to turn it on, off, set brightness, etc?

Would you be able to give samples?

Would you be able to share the commands for brightness and such that you found?

Any idea why the “smartlife.*” as the name? Seems weird given what they did for the plugs.

Hi all… I’m completely new to OpenHab and have just started using OpenHab 2.0 in Mac. I had been trying to use the shell script as mentioned above but not able to bind it. The shell script is working for me (tested using terminal). However, Exec Binding isn’t working (using Paper UI). I am still not clear about what would be the Configuration Parameters - Command and Transform. Would really appreciate if someone could help me out.

Please note my shell script path is /Applications/openhab/conf/scripts/

Thanks

I ran into problems when I added a tp-link smart bulb to my collection of smart plugs on my OpenHab2 window 10 installation. It turns out that the information is different for these two devices. In order to solved this I created a nodejs script that I use to control my tp-link smart plugs and bulbs. More info can be found at https://github.com/veetrik/tplink-handler. I now added support for changing the hue on a color smart bulb (LB130).