Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TP-Link HS110 v3 not working #4

Open
WernerPfalz opened this issue Jul 3, 2019 · 9 comments
Open

TP-Link HS110 v3 not working #4

WernerPfalz opened this issue Jul 3, 2019 · 9 comments

Comments

@WernerPfalz
Copy link

Hi!
I'm running several different HS110s without a problem. Now I just got a new one which doesn't work.
I always get:

Warning: stream_socket_client(): unable to connect to tcp://192.168.0.141:9999 ...

and

Fatal error: Uncaught UnexpectedValueException: Failed to connect to HS110...

After some research I realized that hardware version 2 uses some different encryption. I found a solution from your referenced softScheck-repository.

Here's a link:

[(https://github.com/softScheck/tplink-smartplug/issues/41)]

I've downloaded the softScheck-python-client and replaced:

def encrypt(string):
    key = 171
    result = pack('>I', len(string))
    for i in string:
        a = key ^ ord(i)
        key = a
        result += chr(a)
    return result

with

def encrypt(string):
    key = 171
    result = "\0\0\0"+chr(len(string))
    for i in string:
            a = key ^ ord(i)
            key = a
            result += chr(a)
    return result

This makes the new HS110 as well as the old ones work.

Here's the output of a new HS110:

python tplink_smartplug.py -t 192.168.0.141 -c info
Sent: {"system":{"get_sysinfo":{}}}
Received: {"system":{"get_sysinfo":{"sw_ver":"1.5.4 Build 180815 Rel.121440","hw_ver":"2.0","type":"IOT.SMARTPLUGSWITCH","model":"HS110(EU)","mac":"68:FF:7B:4C:A7:41","dev_name":"Smart Wi-Fi Plug With Energy Monitoring","alias":"TP-Link V3","relay_state":1,"on_time":982,"active_mode":"none","feature":"TIM:ENE","updating":0,"icon_hash":"","rssi":-29,"led_off":0,"longitude_i":0,"latitude_i":0,"hwId":"044A516EE63C875F9458DA25C2CCC5A0","fwId":"00000000000000000000000000000000","deviceId":"80060C4F3D0EF98629D8DA6A675FD82D1B56529B","oemId":"1998A14DAA86E4E001FD7CAF42868B5E","next_action":{"type":-1},"err_code":0}}}

I tried updating your function encrypt($string) in TPLinkDevice.php, but it seams there's something wrong. At least both don't work after my update. Basically the difference in python is the line result = "\0\0\0"+chr(len(string)) instead of result = pack('>I', len(string))

Any help would be great!

@WernerPfalz
Copy link
Author

WernerPfalz commented Jul 3, 2019

I found that changing the inital value of reduce does work on old versions and sometimes on the new, don't really know why!?

protected function encrypt($string)
{
    $key = 171;
    return collect(str_split($string))
        ->reduce(function ($result, $character) use (&$key) {
            $key = $key ^ ord($character);
            return $result .= chr($key);
        },
            "\0\0\0".chr(strlen($string)));
}

@WernerPfalz
Copy link
Author

Here's a little update, I tried using pack instead and convert strlen

protected function encrypt($string)
{
    $key = 171;	
    return collect(str_split($string))
        ->reduce(function ($result, $character) use (&$key) {
            $key = $key ^ ord($character);
            return $result .= chr($key);
        },
			  pack('N', strlen($string)));
}

Main problem is that it takes pretty long and most of the time I get a failed connection.

@WernerPfalz
Copy link
Author

I did some more testing, here's some runtime difference:

"sw_ver":"1.2.5 Build 180410 Rel.182657","hw_ver":"1.0","type":"IOT.SMARTPLUGSWITCH","model":"HS110(EU)"
Total Execution Time: 0.00071203311284383 Mins

"sw_ver":"1.5.4 Build 180815 Rel.121440","hw_ver":"2.0","type":"IOT.SMARTPLUGSWITCH","model":"HS110(EU)"
Total Execution Time: 1.9997138023376 Mins

Really strange, using the modified Python-Code from SoftScheck there's no notable execution-time-difference.

@jonnywilliamson
Copy link
Owner

Ah ok, thanks for this feedback.

Let me have a look at this and get back to you. I don't have a v2 handy here at the moment.

@jonnywilliamson
Copy link
Owner

For reference. Will deal with this soon.

softScheck/tplink-smartplug#22 (comment)

@jonnywilliamson
Copy link
Owner

Here's a little update, I tried using pack instead and convert strlen

protected function encrypt($string)
{
    $key = 171;	
    return collect(str_split($string))
        ->reduce(function ($result, $character) use (&$key) {
            $key = $key ^ ord($character);
            return $result .= chr($key);
        },
			  pack('N', strlen($string)));
}

Main problem is that it takes pretty long and most of the time I get a failed connection.

Ok I've tested this with a V1 hardware and it's working fine.

I found this answer on SO that might help a little https://stackoverflow.com/a/23532422

The differences occurs because of different integer sizes. While L in the php version of pack() uses >hardcoded 32bit integers, Python by default uses the machine integer size. If you are working on a >64bit system you'll notice the difference. (As shown in the question)

So I was wondering if you are using the wrong pack() format.

Would you change the letter N here

  	  pack('N', strlen($string)));

To a "J" and then to an "L" and then to an "I" . (thats a capital 'eye') and see if it makes any difference to the new hardware.

I do not have a v2 or v3 to test unfortunately.

Thanks.

@shanerutter
Copy link

I only have v1 hardware, but I did manage to get my LB110 (light bulb) to respond by changing the pack to the following

strrev(pack('I', strlen($string)))

@shanerutter
Copy link

I only have v1 hardware, but I did manage to get my LB110 (light bulb) to respond by changing the pack to the following

strrev(pack('I', strlen($string)))

Further testing, I found the LB110 has a very high delay while waiting for the response stream. Adding

stream_set_timeout

You are able to control the stream timeout, without this each command was waiting around 30 seconds for a response, I think the TCP connection is left open on the newer units and PHP just sits waiting for further stream content until it ends. Where as the older ones appear to end communication more quickly.

See my branch how I implemented it.

shanerutter@8485ca9

@WernerPfalz
Copy link
Author

Great, stream-timeout solved the delay!
Here are some stats:
V1 Hardware -> Total Execution Time: 0.00020548502604167 Mins
V2 HW with string-lenght-update -> Total Execution Time: 0.98465118408203 Mins
V2 HW with stream-Timeout -> Total Execution Time: 0.084228316942851 Mins
Great solution Shane!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants