I recently acquired a TP-Link HS100 smart plug. Once you install and register the plug and the companion app (Kasa), you’ll be able to do some cool things like turn on/off the plug from your smartphone, schedule on/off at some time. You can also put the plug in Away Mode, so that the plug will randomly turn on/off in the specified time/date interval.
These are already really cool features, but I wanted to be able to do more with it: for example, turn on the plug when I arrive home, and turn it off 5min after I leave home. This is of course out of the scope of the Kasa app features, but I was more thinking about being able to control the plug from a smartphone automation App like Tasker, or a cloud service like IFTTT.
While there are some resources available explaining how to control the TP-Link HS100 plug from another device connected to the same Wifi network, I haven’t been able to find any that would explain how to do it via the TP-Link web service, so this is what I’ll show here.
In this post I’ll show how to change the relay state of the plug via command line from any device connected to Internet, not only from the local Wifi, which can then be called from a script, or from Tasker on Android.
Arquitecture
There are basically 3 components involved here:
- A web service from TP-Link
- The Kasa app that runs on your Smartphone, connected to Internet (via your Wifi network, or any network for that matter). It does (at least) two things:
- Periodically get the status of the plug (is it turned on/off), and show the status in teh app (green icon if the plug is switched on). This happens every two seconds, when the app is in foreground and visible.
- When the user toggles the switch from the app, it will send the new relay state change request to the TP-Link web service.
- The plug, connected to Internet via your wifi network: It will periodically contact the TP-Link web service for any status change, like a request to turn on/off.
Communication overview
This is how the Kasa app communicates itself with the TP-Link web service. In this case when the user switches the plug On, the app will send an HTTP POST request (over SSL) like this one:
POST https://eu-wap.tplinkcloud.com/?token=74adcc7e-64f7-47c1-a751-dece6d2f4704&appName=Kasa_Android&termID=c69d10e5-5307-4602-b2c8-eee8f3761238&appVer=1.4.4.607&ospf=Android+6.0.1&netType=wifi&locale=en_US HTTP/1.1 Content-Type: application/json User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0.1; XXPhoneModelXX) Connection: Keep-Alive Content-Length: 160 Host: eu-wap.tplinkcloud.com { "method":"passthrough", "params":{ "deviceId":"80067AC4FDBD41C54C55896BFA28EAD38A87A5A4", "requestData":"{\"system\":{\"set_relay_state\":{\"state\":1}}}" } }
To which the TP-Link server will respond (when successful):
{ "error_code":0, "result":{ "responseData":"{\"system\":{\"set_relay_state\":{\"err_code\":0}}}" } }
As expected, almost instantly, the plug will switch On.
I have highlighted 4 fields/values in the request above. This values are specific to you and your plug. This is how the TP-Link web service identifies you and which of your plugs you want to switch.
- Token (token=74adcc7e-64f7-47c1-a751-dece6d2f4704): passed in the URL, this is acting as a authentication. The Kasa app obtains it from the TP-Link server when you log in to the service via the App. The user and passwords are not used anymore after that. All communications use the token.
- DeviceID (“deviceId”:”80067AC4FDBD41C54C55896BFA28EAD38A87A5A4″): passed in the Json payload, it references the device we wan’t to control.
- TermID (termID=c69d10e5-5307-4602-b2c8-eee8f3761238): ID of the Client (the Kasa app installed in that particular phone). This doesn’t seem to be a compulsory field.
- state: this is the desired state we want to put the relay into. 1 for On, 0 for Off.
Note: I have changed all the values shown above, to avoid having anyone control my plug by error. I have also formated the Json payloads.
Knowing that, we can now reproduce the same requests, for example using curl, from the command line (even in a Tasker task!). The TP-Link server will have aboslutely no way of telling of the request was originating from the Kasa app or a script.
Now, let see how we can call again the same request from a linux command line using curl. I have removed some parameters, like the User-Agent, and some others in the URL query string, and it still works, so I assume they eventually use them for statistical reasons only:
curl --request POST "https://eu-wap.tplinkcloud.com/?token=74adcc7e-64f7-47c1-a751-dece6d2f4704 HTTP/1.1" \ --data '{"method":"passthrough", "params": {"deviceId": "80067AC4FDBD41C54C55896BFA28EAD38A87A5A4", "requestData": "{\"system\":{\"set_relay_state\":{\"state\":1}}}" }}' \ --header "Content-Type: application/json"
Of course, we need a way to identify the value of this fields. That’s what I’ll cover below.
Data extraction
UPDATE (06/20/2017): this “Data extraction” part is now obsolete. I leave it here for historical purpose. Instead you can now follow the following steps:
OBSOLETE CONTENT STARTS HERE
This is what we’ll need:
- Android phone with Kasa app installed and already registred, with the plug added to the app
- Computer with some tools to unpack the Android Backup file (adb, python, sqlite3,…)
- Phone with adb enabled
First let’s take an Android Backup of the Kasa app:
adb backup -f backup.ab com.tplink.kasa_android
Now let’s unpack the backup with this one-liner:
dd if=backup.ab bs=1 skip=24 | python -c "import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))" | tar -xvf -
Now we just need to find the relevant information. I show you how to retrieve the values for each field:
- Token
$ sqlite3 db/iot.1.db "select token from accounts;"
74adcc7e-64f7-47c1-a751-dece6d2f4704
- deviceID
$ sqlite3 db/iot.1.db "select deviceAlias,deviceID from devices;"My Smart Plug|80067AC4FDBD41C54C55896BFA28EAD38A87A5A4
- termId
$ cat f/INSTALLATION
c69d10e5-5307-4602-b2c8-eee8f3761238
For people on Windows, some users reported in the comments below that you can use Android Backup Extractor (ABE) to extract the backup, instead of dd. See these links:
- https://sourceforge.net/projects/adbextractor/
- https://github.com/nelenkov/android-backup-extractor
- https://forum.xda-developers.com/showthread.php?t=2011811
OBSOLETE CONTENT ENDS HERE
Now, control the plug without the Kasa App
If you follow these steps above you can extract the token and device ID corresponding to your Kasa app and smartplug. You can now control the smart plug from anywhere, without the need to use the Kasa app. For example, you can use the curl expression below, after you replace the values with yours:
- Turn On the plug:
curl --request POST "https://eu-wap.tplinkcloud.com/?token=YOUR_TOKEN_HERE HTTP/1.1" \ --data '{"method":"passthrough", "params": {"deviceId": "YOUR_DEVICEID_HERE", "requestData": "{\"system\":{\"set_relay_state\":{\"state\":1}}}" }}' \ --header "Content-Type: application/json"
- Turn Off the plug:
curl --request POST "https://eu-wap.tplinkcloud.com/?token=YOUR_TOKEN_HERE HTTP/1.1" \ --data '{"method":"passthrough", "params": {"deviceId": "YOUR_DEVICEID_HERE", "requestData": "{\"system\":{\"set_relay_state\":{\"state\":0}}}" }}' \ --header "Content-Type: application/json"
Common issues
- AppServerURL: You’ll need to change the URL used to control the plug with the correct one specific for your plug: See how to find it here.
- [obsolete]{“error_code”:-20580,”msg”:”Account is not binded to the device“}: Some have reported issues with the URL eu-wap.tplinkcloud.com used in this tutorial. Here are all the known (to me) URLs of different TP-Link backend instances. If you have some problem like the previous error, try a different URL:
- use1-wap.tplinkcloud.com if you are near the US region
- aps1-wap.tplinkcloud.com if you are near the Asia Pacific region
- eu-wap.tplinkcloud.com if you are near the Europe region
- wap.tplinkcloud.com, without any region prefix[/obsolete]
- If you get an expired or invalid token error, logout from Kasa app, then login again with your account and extract again the token from the app. Some have needed to uninstall the app completely, reinstall it and start over.
- Be sure to enable Remote Control of the plug. You will find the option in the Kasa App, enter the Plug, then there’s a Plug settings button. There enable Remote control.
If you have any questions or comment, please, do not hesitate to let me know, using the comments below :).
In future posts I’ll show how to integrate your HS100 smart plug with the cloud Automation service IFTTT (see here), and how to control it from the Android Automation app Tasker or your Smartwatch, as well as how to get the state (On/Off) of the plug.