IT Nerd Space

How to control your TP-Link HS100 smartplug from Internet

How to control your TP-Link HS100 smartplug from Internet

How to control your TP-Link HS100 smartplug from Internet

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.

Kasa for Mobile
Kasa for Mobile
Price: Free

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:

  1. Authenticate to TP-Link cloud API and get a token
  2. Get the end point URL and Device ID

OBSOLETE CONTENT STARTS HERE

This is what we’ll need:

  1. Android phone with Kasa app installed and already registred, with the plug added to the app
  2. Computer with some tools to unpack the Android Backup file (adb, python, sqlite3,…)
  3. 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:

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.

  • harvard2006

    Is it possible to learn the token and deviceID with an iphone?

    • admin

      Yes it should be possible, I’ll try to write about it in a future post

    • It should be possible, I’ll try to post about.

      • Craig Poirier

        Yes, I would really appreciate that also. I have no experience in this type of data extraction, so please make it as dummy-proof as possible please 😀

        • Craig Poirier

          FYI, I was able to extract and decrypt the TP-Link file from my iPhone via iExplorer (https://macroplant.com/iexplorer/release-notes?v_major=4&os=pc). Once the file was decrypted and exported to my hard drive, I used Notepad++ to find the token and DeviceID. They were in row 89 of the .db file, although that will likely differ depending on how you view the file.

          • Thanks Craig, great news! I assume this requires Jailbreak, right?

          • Craig Poirier

            No Jailbreak necessary. I didn’t download anything to my phone, and I just opened the backup file from my last iPhone sync. Once I downloaded iExplorer, the decrypting just required my iTunes password.

          • Jim Harry

            Thanks for the tip, Craig. I’m pulling the file, but it doesn’t have anything beyond row ~85, just ‘garbage’. I tried values on 85/86 but i get expired token. Tried logging out/in, deleting the app. When I use a sqlite browser, it shows 0 records for accounts and devices

          • Jim Harry

            Doing a wireshark trace, looks like my iPhone is talking to:
            use1-wap.tplinkcloud.com

          • Jim Harry

            Just as a follow-up, I borrowed a friend’s android tablet and was able to extract the data correctly. Wondering why the iphone data wasn’t there…

          • Craig Poirier

            Boom! I found my other 4 device IDs from the iPhone back-up file within the Kasa app folder. Unlike the initial 2 device IDs I found, the other 4 were harder to find because they didn’t say “deviceId:” next to them. Instead, they all started with 8006, so I did a Ctrl + f to look for other 8006 instances within the Notepad++ file. From there, I did trial and error w/ IFTTT recipes until I figured out which device ID mapped to each device.

            Although it’s great to have everything TP-Link connected to Google Home, it’s going to be pretty cumbersome to reproduce the scenes I easily created in Alexa by grouping my products.

          • Thanks Craig for the pointers!
            Re. IFTTT maybe have a look at Conjure https://beta.conjureapp.com. Not tried myself yet, but looks like it might match your use case here.

          • Jim Harry

            Where else did you find device IDs other than iot.db?

          • Craig Poirier

            They were all in the iot.db file.

          • Jim Harry

            I’d sure like to figure out why my iot.db file contains only a location record. Accounts, Devices, and Scenes tables are all empty. Yet the app works correctly with all four devices I have

          • Craig Poirier

            What did you use to view the db? I initially used SQLite and couldn’t find any records in the tables (accounts, devices, scenes). Knowing there had to be data sitting there, I used Notepad++ to view the file. 99% of the file was junk “Null” and random characters.

          • Jim Harry

            I was using DB Browser for SQLite on the Mac. It shows the structure correctly, but no data. I’ve looked at the file in TextWrangler and didn’t find anything originally. I will go back and look again

          • Jim Harry

            Nope, nothing there. Even used 0xED to look at the byte level. Just no device data in that file from the iPhone.

          • Jim Harry

            For others pulling from the iPhone, the token can be found at the bottom of Library/Preferences/com.tplink.kasa-ios.plist

          • Thanks for reporting that URL as well. I’ve added it top the Common Issues section,it might help others as well.

          • Ben Gunsberger

            Hi Craig, which file are you talking about? The only one I could find was com.tplink.kasa-ios.plist. It has the token but I can’t seem to find the deviceID, even when opening it with plist viewer. Thanks.

    • Nicholas John

      You can proxy it through fiddler its easy.

      • Nicholas John

        Basically you connect to your wifi and get your phone to proxy traffic through fiddler. If you install the fidler certificate it allows fidler to decypt the traffic and if you take a look when opening the kasa app you’ll see it records the device ID and also your token. This works for any phone.

        • Martin N

          Hi Nicholas. Any chance you could explain what you mean about Fiddler to a complete novice like me? Appreciate your help,

          • Nicholas John

            Hi Martin,

            So basically what fiddler does is lets you simulate a “man in the middle” attack. That is to say you’re intercepting traffic before it gets to its destination. In this case its http traffic going to the wifi plug.
            To achieve this we set up our iphone to run through a proxy, fiddler’s proxy. We then install a certificate on the iphone (which we remove later) that allows us to decrypt the traffic.

            Google “how to proxy iphone through fiddler” and they have a guide on their site on how to do this.

          • Nicholas John
  • David Cooke

    Hi Alexandre,

    When I perform the tutorial above I am able to extract all of the information without an issue. When trying to send post commands using my information I receive the following error

    {“error_code”:-20651,”msg”:”Token expired”}

    Any idea what could be causing this problem? Thanks for your help Alexandre.

    • That’s weird. Check that you have enabled the Remote Control of your smart plug (in the Kasa App, open your plug, then it’s settings, and check the Remote control).

      Then, disconnect your phone from your local WiFi (where the plug is connected), you should now be using data connection. Now try the Kasa App, and check that you can turn on/off the plug from the app.

      Try again the curl commands. If it still fails, I’d suggest you go to the Kasa App, menu, View Account, Sign out of Kasa. Then sign in again, and then only, you do again the tutorial above to get the new token and try again.

      Don’t hesitate to report your findings here to help anyone else that may be in the same situation as yours, and so we can help you further if needed.

      • Josiah Eubank

        I am having this issue as well. Have attempted to sign in/out and even reinstall the app/clear data. Immediately upon attempting use the token is expired.

        • Do you have the Kasa App installed on more than one device?

          • Josiah Eubank

            Not the app directly, however Amazon Alexa is connected to the tp-link/kasa system.

          • Joe H

            I’ve had the same problem, I have one app and Alexa connected to TP-Link/Kasa and when I send a CURL or use a REST Client like POSTMAN I get the {“error_code”:-20651,”msg”:”Token expired”} Response, even after uninstalling the app. Maybe activating Alexa on Kasa changes how the authentication works? Looking at the communication from Kasa though, the app uses the same token each time and works fine… strange!

      • Megan Marshall

        Did all these steps, however I’m still getting a token expired error. However, I have the kasa app only installed on my iPhone and nothing else.

        Any idea how to fix this?

        • When I get some time I’ll write how one can do the full process: login(and get token) /getdevices(retrieve deviceid from alias) /power on off.
          I’ve got it working in NodeRed BTW.

  • David Cooke

    I gave this another go, and tried getting a new token, and ensured I can turn the plugs on and off on my cellular network. When trying to run the final terminal input, I am now getting a new error

    {“error_code”:-20571,”msg”:”Device is offline”}

    Not sure why when they are clearly online…Any ideas? Thanks again

    • Martin Bans

      I also ran into the same issue, however I’m based out in Hong Kong so was certain must be related to an Asia based host rather than eu-wap.

      Set up Fiddler to sniff out the POST requests, which are going to https://aps1-wap.tplinkcloud.com

      Works perfectly now.

      • Thanks for reporting back your finding here @martinbans:disqus ! I’ll add the URL later to the post above.

        I can see something of a pattern here in the prefix: use1 (US East 1), aps1 (Asia Pacific Southeast 1),… those are some of AWS region codes. We might find more :).

        We might also find a list, try a DNS lookup and see the corresponding xxx-wap.tplinkcloud.com DNS name is valid or not.

    • I am having the same error. I am based in New Jersey. Kasa app sees and controls my TPLink plugs just fine. But the curl command in this article doesn’t work…

      • Robson Schmidt

        I am in Brazil and having the same error.

  • David Cooke

    Okay ma’man. Coming to you from Canada :>)

    I have identified the problem. Your steps worked well, but the problem lies in the webhook address. I know this because I programmed my router to direct all traffic on a VPN in the Netherlands. When doing so all devices on the network are routed to a VPN in the Netherlands, including my 2 HS100 plugs and my (1) TP-Link HS200 plug. Both are now operational with your tutorial in Canada.

    The problem seems to be with the webhook address. So, that raises my new question…How did you find the webhook address in the EU???

    https://eu-wap.tplinkcloud.com/?token=****DEVICE_ID****

    I would enjoy doing my part to sniff out the North American Address. I tried using a traffic sniffer on android, but it just gave me the IP addresses w ports, geographic location, but nothing static.

    In summary. You are a genius. This completely sychs my Harmony remote Philip Hue Light scenes in 1 command with Amazon Echo VIA IFTTT. I.e. “Alexa, trigger *scene name*” and with multiple IFTTT recipes (2, 1 for the Logitech Harmony scene to cue the scene for Philips Hue, and 1 for turning off the IFTT trigger for TP-Link lights, (white lights that are not smart)”.

    Man that took forever. The VPN is fast, BlackVPN, +100 mbs per second, but isn’t as good as my Gigabit connection. I would really enjoy your input on how to sniff out the webhook address here in North America. Can you push me in the right direction?

    Thanks again for your assistance so far. I am really happy with this progress thus far. You the Man!!!

    David.

  • David Cooke

    Also, there is a known problem with copy and paste functions, meaning, when copying from terminal, the paste isn’t the same. This is a known issue with .sh. Using the original code from the links works with the right device and token details.

  • I have edited the post above and added a Common issues based on people feedback with tips to help solve them.

    • The url wap.tplinkcloud.com actually seem to work for me as well. I guess it’s more generic and will work for anyone then. I will amend both posts to reflect it.

  • Rex Roof

    How were you able to figure out the format of the json payload? I have a tp-link bulb that I’d like to manipulate but the set_relay_state method isn’t supported.

  • vivekkrish

    Hi @adumont:disqus
    Thank you for the wonderful write-up, very easy to follow instructions. It worked well for my HS100 smartplug, when I tried in January!

    I recently bought the new HS105 smartplug mini. Trying to follow the same instructions, I was able to dump the apk contents and extract both the $TOKEN and $DEVICEID from the sqlite DB. However, upon issuing the cURL command, I encountered the following new error from their API:
    {“error_code”:-20580,”msg”:”Account is not binded to the device”}

    Could it be that, they are now checking to see that the web service call is originating from the correct device?

    I’ve tried adding the “termId” value to the JSON payload being posted, but that doesn’t seem to help either.

    Any thoughts?

    Thanks!

    • Unfortunately right now I don’t have any HS105 to test with. I would think the HS105 works like the HS100/110 though. Furthermore the message seems to indicate a problem with your request parameters. I would recommend you follow the “proxy” approach, as explained in another comment here ,(http://itnerd.space/2017/01/22/how-to-control-your-tp-link-hs100-smartplug-from-internet/#comment-3145023762) and check the corresponding requests. Look at the parameters of the request (in the URL), as well as the payload. If you do, please report here, or email me the info you get (redacting any sensitive information), and I’ll write about it.

      • vivekkrish

        Will do! Thanks for your insight on this.

        • try changing the URL. Have a look at the Common Issues section of my post. TP-Link seems to use different back end instances, published at different URLs, at least on in the US, one in Europe and one in Asia Pacific as we’ve discovered so far.

          • Ben Gunsberger

            I’m running into the same problem, trying any of the servers listed (I’m in Australia). @vivekkrish:disqus or @jeffteitelbaum:disqus did you get this working?

          • Can you try this url: aps2-wap.tplinkcloud.com

          • Ben Gunsberger

            Thanks. Turns out I had a typo in my device ID. All working now. FWIW, I don’t have an Android device but was able to use the same method you outline with the BlueStacks emulator on a Mac.

        • Jeff

          @vivekkrish:disqus I’m having the exact same issue with the HS105. Did you ever manage to find a solution? None of the URLs work for me and all throw this error.

  • Rohan Patel

    I’ve made an IFTTT tutorial for the TP-Link light bulb, the LB100.

    See https://sites.google.com/site/phoenixproductionsblender/home-automation/projectarcturus/lb100-ifttt-tutorial.

    • Amazing Rohan. I was trying to acquire a tp-link smartbulb but there’re not in sell here yet.

    • Kian

      Hey Rohan, thanks! Any chance you can look into the LB130, with color options? Any ways to control color options on this? Thanks a bunch!

      • Rohan Patel

        I’ve already done it for the LB130, and it can be controlled the same way as the HS100, but with the color as well. Using hex codes, you can pick 16 million different colors. I didn’t make a tutorial because I figured that few people owned the LB130, but will get to it now. Check back on Arcturus enterprises website soon.

        • charly

          Rohan and Alexandre you are my heroes 😀 I was able to curl to my LB100 !! very happy. Now I’ll try ifttt. But I have a LB130 so very interested in your tutorial about that. THANKS BOTH OF YOU GUYS!!

          • Rohan Patel

            Thanks! I’ll post here when the tutorial is done, which will be on my website arcturusenterprises.weebly.com.

          • charly

            Great! I was able to implement the iftttt stuff with the button, I tried to make it react to an Android event (wifi disconnect) but so far no luck. Will review everything. Hope the token sticks around for a while? Or should I renew it?

  • David Evans

    Hi, when I try to unpack the backup, I get this:
    skip to 24
    14949+0 records in
    14949+0 records out
    Traceback (most recent call last):
    File “”, line 1, in
    TypeError: a bytes-like object is required, not ‘str’
    tar: This does not look like a tar archive
    tar: Exiting with failure status due to previous errors

    What am I doing wrong? Thanks for your help!

    • Hi @disqus_BDL1a542AS:disqus , I don’t know what can be wrong in your case. Maybe something with the Python version… Anyway, you can try an alternative method to extract the Android Backup, using ABE (Android Backup Extractor).

      https://sourceforge.net/projects/adbextractor/

      Run java -jar abe.jar unpack backup.ab backup.tar , then use tar or even 7zip on Windows to extract files from the backup.tar file.

  • Matthew Aguilera

    Help! I cant find the token in the document.

  • Matthew Aguilera

    I found the Device ID but the token is nowhere to be found…

  • Matthew Aguilera

    Can you do this on windows???

    • Not strictly as explained in this post, but you can get the same information as explained in this comment http://itnerd.space/2017/01/22/how-to-control-your-tp-link-hs100-smartplug-from-internet/#comment-3145023762. Then you can use curl on Windows for example.

      • Matthew Aguilera

        I used a different command to unpack the backup and i found the Device ID but i really can’t find the token anywhere i even did multiple Ctrl+F searches with notepad++ which is odd.

        • Could you share the command/tools you used to unpack the backup?

          Do you see the iot.1.db file?

          Regarding the token, did you try the sqlite command?

          sqlite3 db/iot.1.db “select token from accounts;”

          On windows you can use an Sqlite editor

          • Matthew Aguilera

            Im not familiar with a Sqlite editor but i used your command to backup the app and then used an android backup extractor, took the abe.jar file, moved it to the adb folder and typed

            java.exe -jar abe.jar unpack backup.ab backup.tar “” it gave me the iot.1 db file

          • The db file is a database. Check https://sqlitestudio.pl/, open the db file with it and loot at the accounts table in it. You should find the token there hopefully.

          • Matthew Aguilera

            Okay i found the token name under accounts with the data type being VARCHAR and the default value is NULL

          • I assume you’re looking at the Structure tab of the accounts table, just switch to the Data tab, and hopefully you should see the info we’re looking for, the token. ✌️

          • Matthew Aguilera

            Found it! I tried using both the token and deviceid on the maker channel with your other article and it didn’t work for some reason

          • Maybe try a different URL from the one we’ve discovered so far. Check the Common Issues from the post above and see if any works for you 🙂

  • David Cooke

    Hey Alex,

    Its been a while since I’ve checked in. I typically use your method with Amazon Echo, in conjunction with a Harmony Smart Control, IFTTT, Philips Hue lighting system, & Nest.

    In the existing smart home environment, Alexa does have control of Kasa, but cannot be used in conjunction with Philips Hue lighting scenes. Harmony allows one to exhibit scene control in conjunction with Channels, say, on TV, or even movie channels. The Harmony hub, can also turn the heat up with Alex commands in conjunction with Philips Hue. So, a skill in Amazon Echo might be, “Alexa, turn on a movie”, which would cue Logitech Harmony to set the movie channel, cue to Philips Hue to dim the lights in a very low setting, while, changing them red, and turning the heat up, The customization becomes endless.

    The Kasa code you came up with is useful for a variety of reasons, namely, it can controls dumb lights, with smart switches (like the TS100 or TS 200). While these lights can’t change color, they can be told to turn off with the “Alex, turn on a movie” command, which works well with the ambiance or those lights that dim and change color. Conversely, as it relates to the HS100 plug, I use a holiday light that creates animated light patterns on the ceiling during the movie. Pretty cool.

    Thanks again for this. Cheers,

    David.

    • Thanks a lot David for your feedback and for sharing this overview of your smart home setup. Sounds cool !

  • Yuan liao

    Hello, could you please make a more detailed step by step instruction on how to get my token and device ID?

    • What is your context? What phone operating system and computer operating system do you have?

      • Yuan liao

        Hi Alex. I am using iPhone 7 with the most updated IOS 10. I was trying to connect my tp link smart switchs and tp link bulbs to IFTTT. I assume your instruction should also work to achieve my goals as long as I use the right token and device Id. Some says the token and deviceid can be found inside the KASA app in IOS. But i couldn’t.

  • Jon Carroll

    https://uploads.disquscdn.com/images/7e4b075073a7a0d52235139e9379bd41424a3a3c31cff414193d40d8180ce447.png

    am getting blocked (probably user error – am new to Disqus) but thought I’d post a screen grab of my post whilst it’s being moderated …

  • James Scholes

    Just a quick comment here:
    1. If you’re got an encrypted Android device there are a couple of extra hoop to jump through to decrypt the backup. I used https://github.com/nelenkov/android-backup-extractor
    2. I may have an issue as I was seeing: {“error_code”:0,”result”:{“responseData”:”{“system”:{“set_relay_state”:{“err_code”:0}}}”}} (will disqus parse that??) but my switch is toggling fine, despite an error_code: 0 response

    • Thanks for the encryption tip.
      Re. the error code 0, it means “no error” AFAIK ☺️👌

  • Andrew Baldinger

    Quick q: Can you just use a package capture app on android to get the deviceID and Token? It seems much easier than unpacking the backup…

    • True, If you have a rooted phone you can use sqlite3 command line client to run the query, but I found it worth posting this method that work for non root users as well.

      On the packet sniffing app on the phone, I would personally not do that unless I have personally reviewed the source code and compiled myself the app. I otherwise I would definitely not trust it, with all the cookies and stuff that it might sniff as well.

  • HowardRoark

    I’ve unfortunately resigned to the fact that this tutorial just wasn’t written for those not already tech geniuses. I’m usually pretty good following tutorials and figuring stuff out, but this just seems to be missing too much information for even a moderately tech savvy person to work through.

    I performed the adb command and successfully backed up my android files. I don’t know where the backup is located, but I assume who cares since you didn’t mention anything about it.

    I tried the next command in the command prompt and got ‘dd’ invalid syntax. I then realized this is supposed to be a python command…I know nothing about python. So I downloaded and installed python. Opened it up and ran the one-liner you posted. I received the following error:

    ” File “”, line 1
    dd if=backup.ab bs=1 skip=24 | python -c “import zlib,sys;sys.stdout.write(z
    lib.decompress(sys.stdin.read()))” | tar -xvf –
    ^
    SyntaxError: invalid syntax”

    So I give up on Python, and download and install the Android Backup Extractor you mentioned. Then I realized I need to install java to make this work. I know nothing about Java. So I download and install the ‘Java Development Kit with Mission Control’. I open it up and immediately don’t understand where to go.

    So then I go back to command prompt where my adb is located and try the code you gave “java -jar abe.jar unpack backup.ab backup.tar” and it could not find jarfile abe.jar. Then I realize I have to navigate to the Android Backup Extractor folder and run the command again. I then receive the following error:

    Exception in thread “main” java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoa
    der.java:58)
    Caused by: java.lang.RuntimeException: java.io.FileNotFoundException: backup.ab
    (The system cannot find the file specified)
    at org.nick.abe.AndroidBackup.extractAsTar(AndroidBackup.java:420)
    at org.nick.abe.Main.main(Main.java:128)
    … 5 more
    Caused by: java.io.FileNotFoundException: backup.ab (The system cannot find the
    file specified)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(Unknown Source)
    at java.io.FileInputStream.(Unknown Source)
    at java.io.FileInputStream.(Unknown Source)
    at org.nick.abe.AndroidBackup.getInputStream(AndroidBackup.java:501)
    at org.nick.abe.AndroidBackup.extractAsTar(AndroidBackup.java:269)
    … 6 more

    And this is the point where I realize, it just ain’t happening for me. Ironically, this tutorial just isn’t thorough enough for those who aren’t already able to figure this stuff out without needing the tutorial in the first place.

    Guess I will just have to wait for IFTTT or Stringify to add support for TP-LINK!

  • Gavin Lin

    Thanks for the post! This is exactly what I needed and it’s super light-weighted version to control my plug over the internet. I think I am going to hook it up to a cron job to control it at my wish.

    I do run into an issue that others might run into as well:
    My phone is encrypted so when I am creating backups, it has to be encrypted as well. So your oneline python script wouldn’t work. I end-up using the ABE with upgrade JAVA security policy to decrypt the file. The rest just works like a charm.

    Thank you so much!

    -Gavin

    • Gavin Lin

      Oops. Didn’t see someone make the same comments much earlier :p

  • Pete Keleher

    Not able to get token:

    hub:~/Desktop/platform-tools> ./adb backup -f backup.ab com.tplink.kasa_android

    Now unlock your device and confirm the backup operation…

    hub:~/Desktop/platform-tools> lth

    total 10936

    -rw-r—– 1 blah staff 20229 Apr 26 17:21 backup.ab

    hub:~/Desktop/platform-tools> dd if=backup.ab bs=1 skip=24 | python -c “import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))” | tar -xvf –

    20205+0 records in

    20205+0 records out

    20205 bytes transferred in 0.019192 secs (1052783 bytes/sec)

    Traceback (most recent call last):

    File “”, line 1, in

    zlib.error: Error -3 while decompressing data: incorrect header check

    hub:~/Desktop/platform-tools>

    • Is your phone encrypted? In that case, as per the comments of others here, it seems the only way to extract the backup is to use ABE, Android Backup extractor tool.

      • Pete Keleher

        Sorry, I don’t see any such comments…

  • Jeff Axelrod

    Worked great after much effort getting the device/drivers connected to adb and installing the right tools to extract the backup. Thanks so much for this guide! And yes, the encryption was a huge pain in the ass. Also couldn’t authorize the backup because I use a screen overlay (Twilight.) That was a confusing stumbling block!

  • Jeff Axelrod

    I’m having a weird problem; I can control my device just fine when using curl, but when using Google Apps Script’s UrlFetchApp, I’m getting a request timeout response from the tplink server. Google’s servers seem to be communicating with tplink’s just fine–if I change the device ID, I receive a correct error message that “the account isn’t binded [SIC] to the device.”

    The timeout message is this:

    [17-04-28 10:38:49:074 CDT] {“error_code”:-20002,”msg”:”Request timeout”}
    [17-04-28 10:38:49:074 CDT] 200.0

    My code looks like this:

    var TPLINK_ON_PAYLOAD = {
    “method”:”passthrough”,
    “params”: {
    “deviceId”: “XXXX”,
    “requestData”: {
    “system”:{
    “set_relay_state”:{
    “state”:1}}}}}

    function setTplinkState() {
    try {
    var options = {
    ‘method’: ‘post’,
    ‘payload’ : JSON.stringify(TPLINK_ON_PAYLOAD),
    ‘contentType’: ‘application/json’,
    ‘muteHttpExceptions’ : true
    };
    var URL = ‘https://use1-wap.tplinkcloud.com/?token=XXXXXX’;
    var response = UrlFetchApp.fetch(URL,options);
    var responseCode = response.getResponseCode();
    return responseCode;

    • Jeff Axelrod

      No idea why stringify screwed things up, but when I passed requestData as a string directly (shown below), it worked!

      var TPLINK_ON_PAYLOAD = {
      “method”:”passthrough”,
      “params”: {
      “requestData”: “{“system”:{“set_relay_state”:{“state”:0}}}”,
      “deviceId”: “8006D23FB15701EE74723EFD1C789102176BF836”
      }
      }

  • I’ve found out a way for anyone to find out the correct URL to control their plugs, no more hit and miss needed any more! See http://itnerd.space/2017/05/21/how-to-get-the-tp-link-hs100-cloud-end-point-url/.

  • Matthew Aguilera

    When i try entering “dd if=backup.ab bs=1 skip=24 | python -c “import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))” | tar -xvf -” it says that dd is no recognized as a command? sorry kinda a first timer on coding

    • Hi Matt, no shame in being a first timer, we’ve all been there once. I for one still consider I am TBH.

      Are you on Windows? If that’s the case, have a look at Android Backup Extractor (ABE). I’ve put three links in the post about it. Hope that helps.

      • Matthew Aguilera

        I actually tried this before and it didn’t work but i forgot that part thanks for reminding me! I have the token and device id but i can’t find the url because of the command not for windows

  • thewebexpert

    You can install the app aSQLLiteManager on your android if you are rooted, and open the database directly in /data/data/com.tplink…./database and follow the sql commands to run, to get all of your ids. no need to run adb or backups. Thanks so much , worked great!

  • Any idea how to set a timer using a POST method?

    • Hi Jacob, love your idea! I hope that (http://itnerd.space/2017/06/05/remotely-control-your-hs100-timer-api/) answers your question 😉

      • So I’d need to make two calls? one to turn the plug on, then another to turn the timer on to then turn the plug off after a certain amount of time? thanks for the prompt article and response!

        • well that’s how the timer also would work within the Kasa App. You define a timer by telling the action (on/off) to happen after a delay. same here.

          • yeah i just wish there was a way to have the timer be always on. but this should help. thanks.

          • Maybe you are talking about schedules instead? I’ll try to write another post about how to activate schedules and Away mode as well.

          • no your post definitely helped me and i will implement it. any idea if you can control the timer from google assistant?

          • TonyF

            It would be great if one could trigger a Kasa Scene once you have set one up in Kasa.

          • JeremyH

            Yes if you find out please advise,that would help me with my task of turning off multiple devices at nighttime, but at the moment I am assuming the scenes are all self-contained within Kasa and multiple requests are sent from there

  • JeremyH

    Alex, this has been very useful, thank you for he time you have invested in this and sharing with the community. All progressed well, managed to work around the fact that I’m a Windows guy not Linux etc for commands, but JSON is not my thing and I’ve come to an impasse, the script does not work when I run it. I have tried it in Hurl.it, the getDevicelist works so I know the URL and my Token are correct. But when I try to change the switch state I get an error
    {“error_code”:-10100,”msg”:”JSON format error”}

    script is:
    {
    “method”: “passthrough”,
    “params”: {
    “deviceId”: “800676FD5F0A287A6137E090F5DD916D183CXXXX”,
    “requestData”: “{“system”:{“set_relay_state”:{“state”:1}
    }
    }
    ” }
    }

    When I put the JSON script through a validator: https://jsonlint.com/
    I get the error like this…

    Error: Parse error on line 5:
    …”, “requestData”: “{“system”:{“set_
    ———————-^
    Expecting ‘STRING’, ‘NUMBER’, ‘NULL’, ‘TRUE’, ‘FALSE’, ‘{‘, ‘[‘, got ‘undefined’

    ANy ideas what I am doing wrong ? – I copied and pasted the script from the instructions so don’t believe I have a formatting error etc.

    Many thanks

  • JeremyH

    Hi, I am not familiar with JSON is there a way to issue the commands to multiple devices from one script ?- eg a routine that will trigger when I go to bed to turn off various devices etc. when I try the JSON code I get an error due to multiple deviceIDs

    Thanks

  • Check the update in the post!!! The “Data extraction” part is now obsolete. I leave it here for historical purpose. Instead you can now follow the following steps:

    Authenticate to TP-Link cloud API and get a token
    Get the end point URL and Device ID

    (links in the post above)

    • You can’t specify multiple device ID in one command. Use multiple commands (one after the other) with one device ID each. That will do the trick.

      • JeremyH

        thanks but I am not good enough at JSON to figure out how to do this, I have

        {
        “method”: “passthrough”,
        “params”: {
        “deviceId”: “XXX68AF8841FB8C0D29943C00AB1AAC21836XXXX”,
        “requestData”: “{“system”:{“set_relay_state”:{“state”:1} }}”
        }
        }

        {
        “method”: “passthrough”,
        “params”: {
        “deviceId”: “YYYY8AF8841FB8C0D29943C00AB1AAC21836YYYY”,
        “requestData”: “{“system”:{“set_relay_state”:{“state”:1} }}”
        }
        }

        I know this is wrong and won’t work but how do I recode this to make it work ? – do I just use one ‘method’ statement with multiple params ? – can someone give me an example I can learn from please ?

  • JeremyH

    How can I make the script turn off more than one socket ? thanks

    • You can only control one plug per call (one call is one command). So you need to make one call (in other words run one command) for each plug. Does it make sense?

      • JeremyH

        Yes thanks I’ve found that but when I use IFTTT platform for a multiple actions on an applet, the webhooks option only seems to work for the first one (the webhooks applet doesn’t load properly after that), so I was hoping to do it from one script. Basically if I issue a ‘goodnight’ command I want it to turn off everything. any ideas ? thanks

        • Neil Abadie

          Having the same issue here. any advise is greatly appreciated!

        • I don’t think that is possible using only IFTTT and Maker. I can see other options, involving creating a small webservice (that you would invoke from Maker as a webhook), and in which you would “code” all the calls you want (I mean calling as many poweron/off as you like to multiple devices)

          • JeremyH

            thanks yes I was reaching the same conclusion.
            Thanks for the site really useful and enthusing me to try new things.

          • JeremyH

            I’ve found a fix:
            https://medium.com/glitch/how-to-trigger-multiple-applets-in-ifttt-5877860a76af
            works great , would be even better if I could work a timer in. so far I can turn on one night and turn off everything else, but would like to have a timer to turn that light off too after 2 mins or something.

          • Nice Jeremy! I didn’t know this service. It will definitely help all, as one can recreate like a scene and trigger it with one webhook call in Maker. What I didn’t know was the approach they took in Glitch, to trigger IFTTT applets. I was looking into an alternative to Glitch, Webtasks, also free. I’ll try to write up an article about another alternative I know, which might be easier for non programmers, and still do all the steps (including logging in, retrieving the token,…). I only need time to write it…

          • JeremyH

            Yes works well, and doesn’t need any programming skills, I just had to populate the .env file and create a webhooks routine applet for each task. For example create an applet that would turn off kitchen lights, same for kitchen plugs etc, then list these in the .env. Very easy once I’d figured out how to make the instructions work, plus learnt much more about the webhooks service which will help with another challenge I have set myself – I want to remotely control my ageing home burglar alarm via webcalls and an arduino interface … getting there slowly in small steps at present.

          • JeremyH

            PS – as per an earlier post I have found that my token expires and I need to discover the new one, and then that will need embedding to replace the old in each applet again – easy but a bit of a pain, would be happy if anyone has a solution.

  • Rohan Patel

    Alex, I have also found a method of using an Android app that intercepts packets between Kasa app and the devices, which contain information such as deviceID and account token. If you’d like to check it out, it’s at http://arcturusenterprises.weebly.com/find-token–deviceid.html.

  • Neil Abadie

    This is wonderful @adumont:disqus ! Thank you

    I have it working but am new to JSON specifically.

    any quick guidance to switching the state of multiple devices at once?

    {“method”:”passthrough”, “params”: {“deviceId”: “MY_DEVICE_ID”, “requestData”: “{“system”:{“set_relay_state”:{“state”:0}}}”}}

  • Danorano

    This article doesn’t say how to get your Smart Plug token?