Code Monkey home page Code Monkey logo

tplink-smartplug's Introduction

TP-Link WiFi SmartPlug Client and Wireshark Dissector

For the full story, see Reverse Engineering the TP-Link HS110

tplink_smartplug.py

A python client for the proprietary TP-Link Smart Home protocol to control TP-Link HS100 and HS110 WiFi Smart Plugs. The SmartHome protocol runs on TCP port 9999 and uses a trivial XOR autokey encryption that provides no security.

There is no authentication mechanism and commands are accepted independent of device state (configured/unconfigured).

Commands are formatted using JSON, for example:

{"system":{"get_sysinfo":null}}

Instead of null we can also write {}. Commands can be nested, for example:

{"system":{"get_sysinfo":null},"time":{"get_time":null}}

A full list of commands is provided in tplink-smarthome-commands.txt.

Usage

./tplink_smartplug.py -t <ip> [-c <cmd> || -j <json>]

Provide the target IP using -t and a command to send using either -c or -j. Commands for the -c flag:

Command Description
on Turns on the plug
off Turns off the plug
info Returns device info
cloudinfo Returns cloud connectivity info
wlanscan Scan for nearby access points
time Returns the system time
schedule Lists configured schedule rules
countdown Lists configured countdown rules
antitheft Lists configured antitheft rules
reboot Reboot the device
reset Reset the device to factory settings
energy Return realtime voltage/current/power
ledon Turn on the LED indicator
ledoff Turn off the LED indicator

More advanced commands such as creating or editing rules can be issued using the -j flag by providing the full JSON string for the command. Please consult tplink-smarthome-commands.txt for a comprehensive list of commands.

Wireshark Dissector

Wireshark dissector to decrypt TP-Link Smart Home Protocol packets (TCP port 9999).

ScreenShot

Installation

Copy tplink-smarthome.lua into:

OS Installation Path
Windows %APPDATA%\Wireshark\plugins\
Linux/MacOS $HOME/.wireshark/plugins

tddp-client.py

A proof-of-concept python client to talk to a TP-Link device using the TP-Link Device Debug Protocol (TDDP).

TDDP is implemented across a whole range of TP-Link devices including routers, access points, cameras and smartplugs. TDDP can read and write a device's configuration and issue special commands. UDP port 1040 is used to send commands, replies come back on UDP port 61000. This client has been tested with a TP-Link Archer C9 Wireless Router and a TP-Link HS-110 WiFi Smart Plug.

TDDP is a binary protocol documented in patent CN102096654A.

Commands are issued by setting the appropriate values in the Type and SubType header fields. Data is returned DES-encrypted and requires the username and password of the device to decrypt. Likewise, configuration data to be written to the device needs to be sent encrypted. The DES key is constructed by taking the MD5 hash of username and password concatenated together, and then taking the first 8 bytes of the MD5 hash.

Usage

./tddp-client.py -t <ip> -u username -p password -c 0A

Provide the target IP using -t. You can provide a username and password, otherwise admin/admin is used as a default. They are necessary to decrypt the data that is returned.

Provide the command as a two-character hex string, e.g. -c 0A. What type of data a command might read out will be different for various TP-Link devices.

Example

Reading out the WAN link status on an Archer C9 in default configuration shows the link is down (0):

./tddp-client.py -t 192.168.0.1 -c 0E
Request Data: Version 02 Type 03 Status 00 Length 00000000 ID 0001 Subtype 0e
Reply Data:   Version 02 Type 03 Status 00 Length 00000018 ID 0001 Subtype 0e
Decrypted:    wan_ph_link 1 0

tplink-smartplug's People

Contributors

amdhome avatar blndev avatar fuegas avatar kchiem avatar leexiaolan avatar leifnel avatar rirethy avatar smford avatar softscheck avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tplink-smartplug's Issues

Error asking for argument already specified...

What am I doing wrong here?

tplink-smartplug.py –t 10.0.0.127 –c system

usage: tplink-smartplug.py [-h] -t (-c | -j )
tplink-smartplug.py: error: argument -t/--target is required

Tplink KC100 spot ipcam

Tried to use this for KC100. I detected that port 9999 is also open in this device. But i can´t get it to work with the provided commands.

If i wanted to get the video stream from this cam without the need of the app. Think its possible ?

UDP Discovery packet

We are trying to fully automate the connection journey process but cannot get the HS100 unit to reply to UDP broadcast packets. Is there a specific port or message that needs to be broadcast to replicate what Kasa does on OOB conditions? Thanks!

RQ: add MAC to parse commandline arguments

Hi,

we always know HW addr rather then IP. Can you add MAC address as option to parse commandline arguments?

-m as option?

.. and then

!/usr/bin/env python

import commands
ip = commands.getoutput("ip neighbor | grep 'xx:xx:xx:xx:xx:xx' | cut -d ' ' -f 1")

or better way then this..

Update encryption for new firmware/devices

The pyHS100 has a working encrypt/decrypt function in protocol.py which should be used to fixed new firmware/devices issue. See below for the code I literally copied from that project:

# Encryption and Decryption of TP-Link Smart Home Protocol
# XOR Autokey Cipher with starting key = 171
def encrypt(request: str) -> bytearray:
        key = 171
        plainbytes = request.encode()
        buffer = bytearray(struct.pack(">I", len(plainbytes)))

        for plainbyte in plainbytes:
                cipherbyte = key ^ plainbyte
                key = cipherbyte
                buffer.append(cipherbyte)

        return bytes(buffer)

def decrypt(ciphertext: bytes) -> str:
        key = 171 
        buffer = []

        for cipherbyte in ciphertext:
                plainbyte = key ^ cipherbyte
                key = cipherbyte
                buffer.append(plainbyte)

                plaintext = bytes(buffer)

        return plaintext.decode()

Add DNS resolution

Sorry for not doing a merge req, but I'm on a hurry. This is the excerpt

Regards

def validIP(ip):
	match_ip = re.match("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", ip)

	if match_ip:
		try:	
			socket.inet_pton(socket.AF_INET, ip)
		except socket.error:
			parser.error("Invalid IP Address.")
		return ip 
	else:
		try:
			data = socket.gethostbyname(ip)
		except:
			parser.error("Unresolvable DNS Address.")
		return data

Will this work with other smartplugs?

Hi, so I'm looking for a way to get the printer turned off after a finished print and would love to have something like this, the thing is I have a WeMO smart plug, was wondering if it's possible to get this working with other brands?

Thank you

Troubleshooting tplink-smartplug.py

I've purchased and received (today 12/16/2017) a tp-link smart plug HS 100(US) It is version 2.0 according to label on back of device.

I installed the Kasa app on my android phone configuring it for Local only. I didn't create a cloud account. I can turn the switch on and off with the Kasa app.

I cloned the Master branch tplink-smartplug repository. I learned the ip address of the smart plug and tried the tplink-smartplug.py script. I'm apparently not receiving anything back, nor am I seeing an error.

$ ping 192.168.1.79
PING 192.168.1.79 (192.168.1.79) 56(84) bytes of data.
64 bytes from 192.168.1.79: icmp_seq=1 ttl=64 time=2.40 ms
64 bytes from 192.168.1.79: icmp_seq=2 ttl=64 time=2.34 ms
^C
--- 192.168.1.79 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 2.344/2.376/2.409/0.058 ms
$
$ ./tplink-smartplug.py -t 192.168.1.79 -c info
Sent:      {"system":{"get_sysinfo":{}}}
Received:
$
$ telnet 192.168.1.79 9999
Trying 192.168.1.79...
Connected to 192.168.1.79.
Escape character is '^]'.
help
^]

telnet> quit
Connection closed.
$

I've tried info, on and off and also on a couple different hosts. Also tried it with firewall off in case port was blocked. I can telnet to port 9999.

Any suggestions?

Which command to get the runtime values and statistics?

Hi,
using Kasa application, it's possible to get information about energy usage and also about runtime.

I don't find the command to get these statistics (Current runtime, Total runtime, day or month stats about runtime).
Is there any missing commands in the file "tplink-smarthome-commands.txt"?

Other question, the command -energy ( {"emeter":{"get_realtime":{}}} ) gives a value for a parameter named 'current'.
Do you know what the 'current' data is, what is its unit?

Many thanks,

Patrick

Run tplink-smartplug on Windows win_inet_pton

I had occasion to try tplink-smartplug.py on ms windows. I received this error.

> python --version
> Python 2.7.14
[...]
socket.inet_pton(socket.AF_INET, ip)
AttributeError: 'module' object has no attribute 'inet_pton'

I fixed it after reading on StackOverflow Socket has no inet_pton method in Python 2.7 on Windows

pip install win-inet-pton
// and in the .py
import win_inet_pton

Suggestion; Is there a FAQ or some documentation where someone with write privilege could add this?

Extra " in JSON documentation commands, file tplink-smarthome-commands.txt

File tplink-smarthome-commands.txt

Where it says:
Get Montly Statistic for given Year
{"emeter":{""get_monthstat":{"year":2016}}}

It should say:
Get Montly Statistic for given Year
{"emeter":{"get_monthstat":{"year":2016}}}

With the extra ", the call to the command:
./tplink_smartplug.py -t IP_plug -j '{"emeter":{""get_monthstat":{"year":2019}}}'
returns nothing.

Merry Christmas!

Working on Windows

Fun piece of code.

I noticed that socket.inet_pton doesn't work on Window Python 2.7
You have to pip install win-inet-pton and import win_inet_pton

Firmware Versions ...

Hi,

I own 2 HS100-EU . I bought one in 2016 and one quite recently.
I did check the firmware versions on both and the firmware do differ between both:

daniel@j3455:~/source/tplink-smartplug$ ./tplink-smartplug.py -t 192.168.10.244 -c info
Sent:      {"system":{"get_sysinfo":{}}}
Received:  {"system":{"get_sysinfo":{"err_code":0,"sw_ver":"1.1.0 Build 160503 Rel.145047","hw_ver":"1.0","type":"IOT.SMARTPLUGSWITCH","model":"HS100(EU)","mac":"50:C7:BF:xxxxx","deviceId":"80069A202146D1EB3D35C7D8062XXXXXXXXXXXX","hwId":"22603EA5E716DEAEA6642A30BE87AFCA","fwId":"BEF3C9ECA17BF143A7D627AB2D1382C4","oemId":"812A90EB2FCF306A993FAD8748024B07","alias":"Server","dev_name":"Wi-Fi Smart Plug","icon_hash":"","relay_state":1,"on_time":699,"active_mode":"schedule","feature":"TIM","updating":0,"rssi":-42,"led_off":0,"latitude":XXX,"longitude":XXXX}}}
daniel@j3455:~/source/tplink-smartplug$ ./tplink-smartplug.py -t 192.168.10.246 -c info
Sent:      {"system":{"get_sysinfo":{}}}
Received:  {"system":{"get_sysinfo":{"err_code":0,"sw_ver":"1.0.8 Build 151101 Rel.24452","hw_ver":"1.0","type":"smartplug","model":"HS100(EU)","mac":"50:C7:BF:00:FE:AD","deviceId":"80068B6BB6EFEEA4242F4B6XXXXXXXXXXX","hwId":"22603EA5E716DEAEA6642A30BE87AFCA","fwId":"BFF24826FBC561803E49379DBE74FD71","oemId":"812A90EB2FCF306A993FAD8748024B07","alias":"Smarty1","dev_name":"Wi-Fi Smart Plug","icon_hash":"","relay_state":0,"on_time":0,"active_mode":"schedule","feature":"TIM","updating":0,"rssi":-73,"led_off":0,"latitude":XXXX,"longitude":XXXXX}}}

( Anonyminized the GPS coordinates and the deviceID).

As you can see, there are two firmware versions: 1.0.8 (Datestamp: 151101) and 1.1.0 (Datestamp: 160503)
Firmware-Checks in Kasa always for "no new firmware available" for both HS100.

I also checked out your mentioned HS110 (US) Firmware, which is Firmware 1.0.7

Did anyone figured out a way to get updated firmware versions via shd commands ?

Not working on windows 10

I tried to get this to work on my Windows 10 system. I installed the modules in the proper place. But when I tried to import the module it failed. That problem was because the directory name was called TPLink-PlugController-PowerShell-master. But the file in that directory was called TPLink-PlugController-PowerShell.psd1. When I renamed the file TPLink-PlugController-PowerShell-master.psd1 the import module worked.
Next it would not find my smartplug. After a lot of debugging it was determined that my smartplug
was not in the oui.txt file. I added my TP-Link entry with 169182. Now it finds the smartplug.

set_ commands do not seem to work

"model" : "HS110(EU)",
"sw_ver" : "1.5.4 Build 180815 Rel.121440",
"hw_ver" : "2.0", (as reported in the status - but, EU v3.1 on the product label)

I have no problem with any of the get_ commands. However, I have been unable to get the set_ commands to work. They seem too be acknowledged...

$ tplink_smartplug.py -t 192.168.5.113 -j'{"cnCloud":{"set_server_url":{"server":"192.168.5.138"}}}'|grep Receive|sed -e s/Received...//|json_pp
{
   "cnCloud" : {
      "set_server_url" : {
         "err_code" : 0
      }
   }
}

But, nothing happens. Any ideas?

Cannot get working with smartPlug_CE_HS100(AU)_HS110(AU)

Hello everyone.
I have been trying to get this working with an australian version hs100 model
Hardware is version 2 and firmware installed is
smartPlug_CE_HS100(AU)_HS110(AU)_1.1.3_Build_170120_Rel.171906.bin
Checking the firmware sizes from know working models shows it is only 513kb where the woeking models are about 3mb.
Is it possible to check the firmware for the au model and see if there are differences in the command set? I have basic knowledge of wireshark and linux so hoping some smarter people can assist.

Error using JSON commands

ryBook:tplink-smartplug ryanoconnor$ python tplink-smartplug.py -t 192.168.1.225 -j {"emeter":{"get_daystat":{"month":6,"year":2017}}}

usage: tplink-smartplug.py [-h] -t (-c | -j )

tplink-smartplug.py: error: unrecognized arguments: {emeter:{get_daystat:year:2017}}

Any idea why this would be happening?

HS210 3-way Switch Support?

I have a house full of hs100 and hs200 devices. This has worked fantastically for years. I just purchased an HS210 3-way switch. I can do some commands, like status... but ON and OFF do not work.

LB130 RGB Light

I wanted to share some good news that the same TP-Link Smart Home protocol works just about the same on the TP-Link LB130 RGB Light, it's a great light at $50 and pretty efficient in data transfer if you make it local only, I'm starting some dev work to try and sync the lighting to music.

Instead of TCP you'll connect to your light via UDP, and you won't pad the encrypted string with 4 0's at the beginning (or else it won't respond), starting key is still 171.

I copied and made a separate LUA script for the UDP decryption in Wireshark and for the Python if you'd like me to do a pull request.

You can send this string to the light and it does all the real functionality of the light:

{"smartlife.iot.smartbulb.lightingservice":{"transition_light_state":{"saturation:"100,"brightness":100,"mode":"normal","ignore_default":1,"color_temp":0,"hue":360,"on_off":1,"transition_period":3000}}}

Saturation and Brighness are 0-100, Hue is 0-360, on_off turns the light on or off (a brightness of 0 will still have some brightness), color_temp sets the color temperature.

Transition Period is the best functionality because it's not already included in the Kasa app. You can set the delay in milliseconds for fading between colors. I'm working on a UWP app for Windows 10.

Unable to communicate with the HS110 plug anymore

Even a simple command to get the system info:

python tplink_smartplug.py -t 192.168.1.2 -p 9999 -j 'info'

returns "Cound not connect to host 192.168.1.2.:9999".

Recently I have installed the new firmware update v. 1.5.6 for the HS110 2.0 model. Could that be the reason?

I have also noticed that recently you have pushed a commit giving the possibility to pass a different port number. Did TPLink change the port? Btw, I have tested the latest version of the script and I still get the same error message.

Simulation of an LB130 or sth. else

Hi, currently i'm trying to simulate a TP-Link smart lamp, because want to use own hardware which can talk with the tp-link protocol (hopefully including the cloud functionality)

I don't know what i'm doing wrong here, because i can see the try of the discovery in the commandline of the Kasa android app. The virtual Lamp won't be found in the app, but the search request is arrived in the simulation. Something seems to be missing.
Can you please take a look?

const dgram = require('dgram');

const socket = dgram.createSocket({
  type: 'udp4',
  reuseAddr: true
});

function encrypt(input, firstKey) {
  if (typeof firstKey === 'undefined') firstKey = 0xAB;
  var buf = new Buffer(input.length); // node v6: Buffer.alloc(input.length)

  var key = firstKey;
  for (var i = 0; i < input.length; i++) {
    buf[i] = input.charCodeAt(i) ^ key;
    key = buf[i];
  }
  return buf;
};

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;
};


socket.on('error', function (err) {
  console.error('Client UDP error');
  console.trace(err);
  socket.close();
}.bind(this));

const systemData = {
  "system":{
  "get_sysinfo":{
  "sw_ver":"1.4.3 Build 170504 Rel.144921",
  "hw_ver":"1.0",
  "model":"LB130(EU)",
  "description":"Smart Wi-Fi LED Bulb with Color Changing",
  "alias":"TestLamp",
  "mic_type":"IOT.SMARTBULB",
  "dev_state":"normal",
  "mic_mac":"50C7xxxxxxxx",
  "deviceId":"8012459DB0CAAAB0FACF605DC492xxxxxxxxxxxx",
  "oemId":"D5C424D3C480911C980Exxxxxxxxxxxx",
  "hwId":"111E35908497A05512Exxxxxxxxxxxxxx",
  "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":120,
      "saturation":100,
      "color_temp":0,
      "brightness":10
    }
  },
  "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":-21,
      "active_mode":"none",
      "heapsize":332364,
      "err_code":0
    }
  }
};

const lightDetailsData = {
  "on_off": 1,
  "mode": "normal",
  "hue": 120,
  "saturation": 100,
  "color_temp": 0,
  "brightness": 100,
  "err_code": 0
};

const lightStateData = {
  "on_off": 1,
  "mode": "normal",
  "hue": 120,
  "saturation": 100,
  "color_temp": 0,
  "brightness": 100,
  "err_code": 0
};

socket.on('message', function (msg, rinfo) {
  const decryptedMsg = decrypt(msg).toString('ascii');
  //const request = JSON.parse(decryptedMsg);

  var data = '{}';

  if(decryptedMsg.indexOf('"system":{"get_sysinfo":{') != -1) {
    data = JSON.stringify(systemData);
  }
  else
  if (decryptedMsg.indexOf('"smartlife.iot.smartbulb.lightingservice":{"get_light_details":{') != -1) {
    data = JSON.stringify(lightDetailsData);
  }
  else
  if (decryptedMsg.indexOf('"smartlife.iot.smartbulb.lightingservice":{"transition_light_state":{') != -1) {
    data = JSON.stringify(lightStateData);
  }

  console.log('REQUEST:\n' + decryptedMsg);
  console.log('FROM:\n' + rinfo.address + ':' + rinfo.port);
  console.log('ANSWER:\n' + data);

  var msgBuf = encrypt(data);

  socket.send(msgBuf, 0, msgBuf.length, rinfo.port, rinfo.address);

}.bind(this));

socket.bind(9999);

Thank you in advance for your help!

Empty result?

Here is what I get from a jason query, did I do anything wrong?
The script runs fine with "-c info" and returned meaningful result.

./tplink-smartplug.py -t <HS110_IP> -j {"emeter":{"get_realtime":{}}}
('Sent: ', '{emeter:{get_realtime:{}}}')
('Received: ', '')

Thanks. How does calibration work please ?

Hello,
Wonderfull stuff. Thanks

I can make it work.
Out of factory readings are very far from 220V
So I changed vgain

Nevertheless I saw there was a calibration command
What are the units of vtarget and itarget ?

Start EMeter Calibration{"emeter" "start_calibration" "vtarget":13462,"itarget":16835}}}

I am guessing the two values should be those known from a device that does
draw vtarget volt and itarget amps exactly ?
And then vgain and igain would be set automatically ?

Example above is confusing since 13462 is the same value as vgain value in ´´the manual´´,
and 13462 is like 1.3462 that is a diviser to adjust the voltage

Thanks

Flash firmware via tplink-smartplug

Hi,

I am having trouble upgrading my firmware on the HS100(EU) with the Kasa App and don't own a Windows PC to use the upgrade tool. So I tried to download the "hs100v1_eu_1.1.3_Build_170608_Rel.204734.bin" from the "iotUpgradeTool_V1.0" tool to my plug via your tool.

python tplink-smartplug.py -t IP -j '{"system":{"download_firmware":{"url":"https://someURL/hs100v1_eu_1.1.3_Build_170608_Rel.204734.bin"}}}'

But I get the following:

Sent: {"system":{"download_firmware":{"url":"https://someURL/hs100v1_eu_1.1.3_Build_170608_Rel.204734.bin"}}} Received: {"system":{"download_firmware":{"err_code":0}}}

and when I try to check the download state I get

Sent: {"system":{"get_download_state":{}}} Received: {"system":{"get_download_state":{"err_code":-7,"err_msg":"unknown error"}}}

Did anybody tried it before? Does the URL need to point to a tplinkcloud.com URL?

How to for Default OFF?

On power loss, I noticed that when the power comes back it retains the previous state (on if it was on and off if it was off).
Is there a way to set it so the default is OFF (when the power comes back)?

Broadcast state changes

Mostly thinking out loud here... Does anyone know if the tplink smart plug can automatically broadcast or send changes in relay_state or must it be queried? I don't see any snmp trap support and no place to enter an IP Address for a remote receiver. So, it appears this may not be possible. OTOH, perhaps there is a way to create a local "cloud server" and maybe that might work.

Latest Firmware changes 4 byte prefix

I bought a H110 UK version plug, ran the firmware update and discovered this no longer works. However, after running a packet capture on my phone, I can see that the four byte prefix is no longer

0x00 0x00 0x00 0x00

but

0x00 0x00 0x00 0x2a

And making that change to the encode function of this https://github.com/EgoManiac/TPlink-PoSH

made it work again.

add retry loop

First of all, thank you for posting this simple code thatvworked out of the box for me. I am facing one issue when querying the plug repeatedly every 5 or 10 seconds. After 20 successful queries, I randomly get socket errors that cause the script to terminate. I tried inserting a retry loop but can't get a better result. Any ideas how to address this issues? Inserting a retry loop might help...

Not working on latest hardware v3.0, firmware v1.5.2

I can't get the script running on a newly purchased HS110(EU).
Device label says it's HW v3.0, Kasa app however says it's HW v2.0... Firmware is on 1.5.2 (Build 180130) as per Kasa info.

If I send a request I get an empty response:
MacBook-Pro:~ user$ downloads/tplink-smartplug-master/tplink-smartplug.py -t 192.168.5.xx -c on
Sent: {"system":{"set_relay_state":{"state":1}}}
Received:

Running the same thing on my trusty HS100(EU) v1.0 on FW v1.1.3 is working as intended.
MacBook-Pro:~ user$ downloads/tplink-smartplug-master/tplink-smartplug.py -t 192.168.5.xx -c on
Sent: {"system":{"set_relay_state":{"state":1}}}
Received: {"system":{"set_relay_state":{"err_code":0}}}

Just randomly sending requests to other devices gives me the following:
MacBook-Pro:~ user$ downloads/tplink-smartplug-master/tplink-smartplug.py -t 192.168.5.xx -c info
Cound not connect to host 192.168.5.xx:9999

Port 9999 therefore seems to be open on new versions, but it looks like TP-Linked changed something in between.

Size of answer from device limited to 1024 bytes

Hello!

I have just get my hands on a pair of new HS110(EU), updated to most recent firmware, and while experimenting with the python tool I concluded that the device will split the answer whenever the answer has more than 1024 bytes. This particular case occurs if you have programmed several many schedule rules and then you send a '{"schedule":{"get_rules":{}}}'.

I made a few modifications to the script, to ensure that all data will be retrieved. Bellow is the new code for receiving the answer from the device. Feel free to incorporate it.

data = sock_tcp.recv(1024)
len_data = unpack('>I', data[0:4])
while (len(data) - 4) < len_data[0]:
	data = data + sock_tcp.recv(1024)

Regards,
Fernando

How to change hostname

Is there a way to change the hostname name of the device? I saw in the python code allowing for using hostname to contact the device but not a direct command for changing it.

Two very minor issues with README.md

I noticed two very minor issues with README.md:

  1. In the first section ("tplink-smartplug.py") the Usage example references a different name for the python script:

./tplink-smarthome.py -t <ip> [-c <cmd> || -j <json>]

That should be tplink-smartplug.py to match the file in the repo.

  1. In the Command table just below that, it lists the system command with description Returns device info. In fact, the info command does that and the system command is not recognized:
$ ./tplink-smartplug.py -t 192.168.0.229 -c system
usage: tplink-smartplug.py [-h] -t <ip> (-c <command> | -j <JSON string>)
tplink-smartplug.py: error: argument -c/--command: invalid choice: 'system' (choose from 'reset', 'schedule', 'antitheft', 'wlanscan', 'info', 'on', 'off', 'reboot', 'countdown', 'time', 'cloudinfo')
$ ./tplink-smartplug.py -t 192.168.0.229 -c info
Sent:      {"system":{"get_sysinfo":{}}}
Received:  {"system":{"get_sysinfo":{"err_code":0,"sw_ver":"1.1.1 Build 160725 Rel.163650","hw_ver":"1.0","type":"IOT.SMARTPLUGSWITCH","model":"HS100(US)",...

Awesome tool, loved the Reverse Engineering document.

HS300 returns 5 children (plugs), when 6 is expected

The HS300 has 6 outlets.

When I send command:
./tplink_smartplug.py -t HS300 -c info

I receive:
Sent: {"system":{"get_sysinfo":{}}} Received: {"system":{"get_sysinfo":{"sw_ver":"1.0.10 Build 190103 Rel.163517","hw_ver":"1.0","model":"HS300(US)","deviceId":"<obfuscated>","oemId":"<obfuscated>","hwId":"<obfuscated>","rssi":-68,"longitude_i":<obfuscated>,"latitude_i":<obfuscated>,"alias":"TP-LINK_Power Strip_0320","mic_type":"IOT.SMARTPLUGSWITCH","feature":"TIM:ENE","mac":"<obfuscated>","updating":0,"led_off":0,"children":[{"id":"<obfuscated>00","state":0,"alias":"outside fan","on_time":0,"next_action":{"type":-1}},{"id":"<obfuscated>01","state":1,"alias":"inside fan","on_time":1352807,"next_action":{"type":-1}},{"id":"<obfuscated>02","state":1,"alias":"Plug 3","on_time":1398685,"next_action":{"type":-1}},{"id":"<obfuscated>03","state":1,"alias":"Plug 4","on_time":1398685,"next_action":{"type":-1}},{"id":"<obfuscated>04","state":1,"alias":"Plug 5","

as you can see it stops at Plug 5, and it doesn't finish

When I change
data = sock_tcp.recv(2048)
to
data = sock_tcp.recv(4096)

I then receive all 6 children. Was this the correct fix?

TpLink HS300 Powerstip

Hello. Just wondering if anyone has commands for the HS300 powerstrip. Purchased one today, it uses many of the commands from the HS1xx plug series, but need to know how to control individual relays.

Thanks

Hello,
Thank you for sharing this source - it was pivotal to integrating my HS100 smart plugs into openHAB 1.8.3

HS103 and KP400

Hi,

I just wanted to report that I've been using the script with the HS103 and KP400, and it's been working perfectly, although I've only used some basic functionality: the "on", "off" and "info" commands, and commands like
tplink_smartplug.py -t 192.168.xx.xx -j '{"netif":{"set_stainfo":{"ssid":"my-iot-ssid","password":"my-iot-wifi-password","key_type":3}}}'"

Incidentally, while I use Home Assistant to control my HS103s on a regular basis, the HA TP-Link integration seems to be badly broken for the KP400, so I'm currently controlling my KP400 via cron jobs firing off tplink-smartplug.py invocations ;)

Thanks very much for this code (and very informative and readable blog post)!

Turning on from a raspberry pi

Hi,

Very noob question. I was wondering how to turn the smartplug on from a raspberry pi. I have the python script in the root directory of my pi. I am running the following command:

bash tplink_smartplug.py -t 192.168.0.245 -p 9999 {"system":{"get_sysinfo":null}}

tplink_smartplug.py: line 22: import: command not found
tplink_smartplug.py: line 23: import: command not found
tplink_smartplug.py: line 24: import: command not found
from: can't read /var/mail/struct
tplink_smartplug.py: line 27: version: command not found
tplink_smartplug.py: line 30: syntax error near unexpected token (' tplink_smartplug.py: line 30: def validHostname(hostname):'

Thanks

THANK YOU (plus a question on skewed energy monitoring)

I've spent the afternoon trying to sniff the https comms from the android app to see the API commands it was issuing to the smartplug ... and eventually found your repo.

A thousand thanks! I'm now finally able to solve a very pesky problem.

Unrelated question, if I may. I have a nifty frequency inverter running on a HS110 smartplug with energy monitoring. The problem is that the HS110 energy monitoring is sometimes reading completely erratic values for the power (so either current, voltage, or both). Every once in a while, instead of a constant 264-266W power draw, it jumps to something like a few tens of million W for like half a second. This is enough to completely skew all energy measurements for the day or the total, making it look like I'm consuming the entire planet's energy supply, see screenshot below.

What do the Igain and Vgain do exactly? Can this issue be fixed by changing those values?

Please help fix error

I have Python 2.7 64bit
windows 10 64bit

Whe i type:
tplink-smartplug.py –t "192.168.100.115" –c "on"

I get:
C:\test>tplink-smartplug.py -t "192.168.100.115" -c "on"
Traceback (most recent call last):
File "C:\test\tplink-smartplug.py", line 76, in
args = parser.parse_args()
File "C:\Python27\lib\argparse.py", line 1701, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "C:\Python27\lib\argparse.py", line 1733, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "C:\Python27\lib\argparse.py", line 1939, in _parse_known_args
start_index = consume_optional(start_index)
File "C:\Python27\lib\argparse.py", line 1879, in consume_optional
take_action(action, args, option_string)
File "C:\Python27\lib\argparse.py", line 1791, in take_action
argument_values = self._get_values(action, argument_strings)
File "C:\Python27\lib\argparse.py", line 2231, in _get_values
value = self._get_value(action, arg_string)
File "C:\Python27\lib\argparse.py", line 2260, in _get_value
result = type_func(arg_string)
File "C:\test\tplink-smartplug.py", line 30, in validIP
socket.inet_pton(socket.AF_INET, ip)
AttributeError: 'module' object has no attribute 'inet_pton'

How to control the plug remotely

Hi,

Just wondering is there any way to control the plug through Internet? The code works for me in my home wifi, but I want to control the plug outside, just like the Kasa app.

Thanks!

[Request] Better handling of JSON -j option

Great script, just wanted to mention the -j option doesn't work unless you escape the "s .
Example:
tplink-smartplug.py -t <IP> --json {"system":{"get_sysinfo":null}}
should be typed out as
tplink-smartplug.py -t <IP> --json {\"system\":{\"get_sysinfo\":null}}
or simply
tplink-smartplug.py -t <IP> --json '{"system":{"get_sysinfo":null}}' (note the surrounding 's)

Maybe have the script better handle the input?

opening the whole thing ( got root )

Thanks for decrypting the default password.
i soldered on a tty and got root on the thing.

in case you want me to try anything before i try flashing upstream linux, let me know.

schedule

how does the schedule work?
what are stime_opt, smin, etime_opt, emin, eact keys ?
thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.