Joshua's Docs - TP-Link Cloud, Kasa, TP-Link Smart Products - Dev Cheatsheet
Light

Amazon:

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:

Unofficial Integrations

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 of application/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}}"
      	}
      }
  • Get Device List
    • Path: /
    • Method: POST
    • Payload:
      {
      	"method": "getDeviceList",
      	"params": {
      		"token": "{{KASA_Token}}"
      	}
      }
  • 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.
  • 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}}"
      	}
      }
  • Power Strip: Turn individual plugs on and off
    • Path: /
    • Method: POST
    • Payload (sample):
      {
      	"method": "passthrough",
      	"params": {
      		"deviceId": "{{Device_ID}}",
      		"requestData": {
      			"context": {
      				"child_ids": [ "{{Plug_ID}}" ]
      			},
      			"system": {
      				"set_relay_state": {
      					// 0 = off, 1 = on
      					"state": 0
      				}
      			}
      		},
      		"token": "{{KASA_Token}}"
      	}
      }
    • I have not tested this, but this is based on A, B, C, and D.
    • To get Plug_ID, based on this comment and this code as well as this code, it should be the Device_ID of the entire strip, plus 2 digits (zero-left-padded, zero-indexed) corresponding to the numerical order of the plugs
      • For example, if the ID of your entire strip is ABC, then the very first plug would have a Plug_ID of ABC00, the second would have ABC01, and so on.
    • I'm not sure if child_ids will work with more than one plug ID at a time - you would think since it is an array that passing more would work and turn all IDs on or off based on the system payload, but without a device I can't test this

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 uses POST / with payload {"method": "getDeviceList", "params": { ... }}
    • Another oddity is that the nested requestData object (e.g. for passthrough 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 stringified requestData payloads, but as of 7/2020, it seems fine with regular JSON objects.
  • 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}
    • 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 as appType and the User-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).

Android Client

  • Checkout Sternbach-Software/KasaTPLinkAndroidSDK for an unofficial Android SDK
  • I've pulled a recent AndroidManifest.xml - here (EDIT: This is now quite old and possibly outdated)
    • 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?)
Markdown Source Last Updated:
Sun Jan 21 2024 05:00:50 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Thu Jan 02 2020 02:27:51 GMT+0000 (Coordinated Universal Time)
© 2024 Joshua Tzucker, Built with Gatsby
Feedback