KASA Device Purchase Links
Amazon:
KASA vs TP-Link Cloud
Assuming you allow for non-local use, TP-Link Cloud is basically what bridges the connection between your local network (TP-Link physical devices) and the "cloud", and seems to be what maintains the mesh of devices and their API communications.
Kasa is really just an App, and some branding for TP-Link smart devices, and mostly does just two things:
- Allows you to manage the TP-Link cloud and register new devices
- Provides a GUI for turning things off and on
Kasa itself is using the TP-Link Cloud API, which is discussed further below, since it can be used unofficially as a way to interact with physical TP-Link products / Cloud, without requiring being connected to the same router / LAN.
Official Integrations
At the time of researching, it was hard to find one spot for this info, but it appears that the official integrations are:
- IFTTT
- Google Home
- Samsung SmartThings
- Amazon Alexa
- Brilliant (Smart Home App)
Unofficial Integrations
-
By hand approaches
-
Libraries:
-
Local / LAN
- Node / NPM - Patrick Seal: plasticrake/tplink-smarthome-api
- Python - python-kasa
-
TP-Link Cloud
-
Node / NPM - Alexandre Dumont: adumont/tplink-cloud-api
- This is an impressive use of the unofficial API. Dumont also has documented a lot of the API in blog posts at itnerd.space.
-
-
-
Other
-
TP-Link Cloud
- Google Apps Script: I created a Google Apps Script wrapper around the API. You can read more about it here. This also let me more fully integrate it with Android.
-
TP-Link Cloud API - Dev Cheatsheet
Endpoints and Methods
Main API Base URL:
-
https://wap.tplinkcloud.com
- OR (?)
https://use1-wap.tplinkcloud.com
As noted below on "general usage", the API is a little unique in that all methods share the same path (just
/
, the base URL), and the methods are passed in the body / payload, rather than in the path itself. For example, there is no endpoint like/turnDeviceOn
- instead you have to pass a carefully crafted JSON payload to turn devices on.
The placeholder
{{variable_name}}
indicates a place where you need to replace the{{...}}
with your unique value.
Use a
Content-Type
header, with value ofapplication/json
, for all of these requests.
Endpoints / Methods:
-
Get Auth Token (these expire):
- Path:
/
- Method:
POST
-
Payload:
{ "method": "login", "params": { "appType": "Kasa_Android", "cloudUserName": "{{KASA_User}}", "cloudPassword": "{{KASA_Pass}}", "terminalUUID": "{{$guid}}" } }
- Path:
-
Get Device List
- Path:
/
- Method:
POST
-
Payload:
{ "method": "getDeviceList", "params": { "token": "{{KASA_Token}}" } }
- Path:
-
Turn a device on/off
- Path:
/
- Method:
POST
-
Payload:
{ "method": "passthrough", "params": { "deviceId": "{{Device_ID}}", "requestData": { "system": { "set_relay_state": { "state": 0 } } }, "token": "{{KASA_Token}}" } }
- Note: Use
"state": 0
for off, and"state": 1
for on.
- Path:
-
Get device status
- Path:
/
- Method:
POST
-
Payload (sample):
{ "method": "passthrough", "params": { "deviceId": "{{device_id}}", "requestData": { "system": { "get_sysinfo": null }, "emeter": { "get_realtime": null } }, "token": {{KASA_Token}} } }
- Path:
These are subject to change. Currently, the best maintained place to find up-to-date info on the API is probably
adumont/tplink-cloud-api
, or the related blog posts on itnerd.space.
Notes on usage
-
General usage:
-
The API is a little unique in that it uses the pattern of differentiating between actions by values in the payload, rather than different endpoints / URL paths
- The action is passed in with the key of
method
- For example, rather than using something like
GET /deviceList
, it usesPOST /
with payload{"method": "getDeviceList", "params": { ... }}
- The action is passed in with the key of
-
Another oddity is that the nested
requestData
object (e.g. forpassthrough
method) can be passed either as a single stringified value, or as a regular nested JSON object. Changing the type actually affects the shape of the response data (e.g. sending stringified JSON results in a stringified response, and vice-versa).- The
adumont/tplink-cloud-api
code makes it look like, at one point or another, the API might have only accepted stringifiedrequestData
payloads, but as of 7/2020, it seems fine with regular JSON objects.
- The
-
-
Token sending options
-
It looks like the auth token can be sent either in the URL itself or in the JSON body
- URL:
___/?token=TOKEN
- Body:
{params: {token: TOKEN}
- URL:
- For security reasons, you should pretty much always opt to send tokens as part of a payload, rather than in the URL, so they can't be sniffed (assuming valid HTTPS)
-
-
terminalUUID / UUID
- This does not need to be a specific ID, nor does it need to be generated as a unique ID each time.
- If you are using POSTMAN to mock, you can use the
{{$guid}}
macro to generate a unique ID
-
What is the purpose of
Kasa_Android
asappType
and theUser-Agent
header?- Most of the API docs available by the community rely on endpoints exposed by reverse-engineering the Kasa smartphone app. At any point, TP-Link could start cracking down on suspicious API requests, so "spoofing" the official Kasa app is a way to minimize the risk of your request getting blocked.
-
Based on
tplink-cloud-api
, here are good values:appType
:Kasa_Android
-
User-Agent
:Dalvik/2.1.0 (Linux; U; Android 6.0.1; A0001 Build/M4B30X)
(really, this could be any modern valid Android UA that Kasa can run on)- In fact, this should actually probably be something with
Android 8.0.0
or higher in the string, as anything lower has already reached EOL (as of 2020).
- In fact, this should actually probably be something with
Android Client
-
I've pulled a recent AndroidManifest.xml - here
- I tried to spoof a related intent to the On/Off widget but could not get it to work (I think some of the Android action strings might be blocked from spoofing?)