adumont / tplink-cloud-api

A node.js npm module to remotely control TP-Link smartplugs (HS100, HS110) and smartbulbs (LB100, LB110, LB120, LB130) using their cloud web service (no need to be on the same wifi/lan)
https://itnerd.space
GNU General Public License v3.0
129 stars 44 forks source link

P100 support #42

Open spasea opened 3 years ago

spasea commented 3 years ago

Hey, @adumont

I'm wondering: can tp link p100 be controlled through tplink cloud api? I tried to use HS100 interface, but I've got such response while trying to set relay state to 0 (basically each response was like this)

{
    "error_code": 0,
    "result": {
        "responseData": {
            "error_code": -1003
        }
    }
}

Also this device is visible in my account devices list. I did some proxy inspection on my phone and found out, that request payload was a bit different from the HS100 one. Mine contained securePassthrough method and encrypted requestData. I think it can be different because it was communicating through local network, but I can be wrong.

Any comment would be appreciated 🙂

adumont commented 3 years ago

It's possible that the Kasa app talks directly to the device if it's found on the same wifi. Can you put it on another wifi? (or put your phone on another wifi).

El vie., 13 nov. 2020 18:43, Peter Smaznoy notifications@github.com escribió:

Hey, @adumont https://github.com/adumont

I'm wondering: can tp link p100 be controlled through tplink cloud api? I tried to use HS100 interface, but I've got such response while trying to set relay state to 0 (basically each response was like this)

{

"error_code": 0,

"result": {

    "responseData": {

        "error_code": -1003

    }

}

}

Also this device is visible in my account devices list. I did some proxy inspection on my phone and found out, that request payload was a bit different from the HS100 one. Mine contained securePassthrough method and encrypted requestData. I think it can be different because it was communicating through local network, but I can be wrong.

Any comment would be appreciated 🙂

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/adumont/tplink-cloud-api/issues/42, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACRLWSQ3DVVPUMZLFHGIU3SPVV5FANCNFSM4TU3N5YA .

spasea commented 3 years ago

@adumont ok, I'll try it

spasea commented 3 years ago

@adumont I was able to do some debug and found out 2 actions I needed To get status of the switch - the following request data required

{
    "method": "passthrough",
    "params": {
        "deviceId": "***id***",
        "requestData": {
            "method": "get_device_running_info",
            // without these 2 parameters everything worked as well
            "requestTimeMils": 1605366971489,
        "terminalUUID": "34-82-B1-3A-23-F2"
        }
    }
}

And response would be like the following

{
    "error_code": 0,
    "result": {
        "responseData": {
            "result": {
                "rssi": -44,
                "time_usage_today": 432,
                "latitude": number,
                "ip": "device_ip",
                "device_on": true,
                "avatar": "table_lamp",
                "time_usage_past30": 725,
                "has_set_location_info": false,
                "time_usage_past7": 725,
                "signal_level": 3,
                "on_time": 399,
                "overheated": false,
                "nickname": "QmVkIGxhbXA=",
                "location": "bedroom",
                "fw_ver": "1.2.1 Build 20200616 Rel. 31218",
                "longitude": number
            },
            "error_code": 0
        }
    }
}

To set the switch status you have to pass these parameters

{
    "method": "passthrough",
    "params": {
        "deviceId": "***id***",
        "requestData": {
            "method": "set_device_info",
            "params": {
                "device_on": true || false
            },
            // without these 2 parameters everything worked as well
            "requestTimeMils": 1605366971489,
        "terminalUUID": "34-82-B1-3A-23-F2"
        }
    }
}

And response would be as the following

{
    "error_code": 0,
    "result": {
        "responseData": {
            "error_code": 0
        }
    }
}

Currently I don't have much time to do a pull request, but in some future I'll try to do a contribution

cjdshaw commented 3 years ago

I have a couple of P100s, but they show up in my deviceList with base64 encoded aliases, and status as offline

{
  "error_code": 0,
  "result": {
    "deviceType": "SMART.TAPOPLUG",
    "role": 0,
    "fwVer": "1.3.3",
    "appServerUrl": "https://eu-wap.tplinkcloud.com",
    "deviceRegion": "eu-west-1",
    "deviceId": "####",
    "deviceName": "P100",
    "deviceHwVer": "1.0",
    "alias": "RnJvbnQgZG9vciBsaWdodHM=",
    "oemId": "####",
    "deviceMac": "####",
    "deviceModel": "P100",
    "hwId": "####",
    "fwId": "####",
    "isSameRegion": true,
    "status": 0
  }
}

If I try to do anything with them, I just get

{
  "error_code": -20571,
  "msg": "Device is offline"
}

I wonder why yours are different

spasea commented 3 years ago

@cjdshaw I have another p100 socket with hardware version 1.0. Here you have another api endpoint with different request/response structure. Basically you should hit another endpoint url. You can trace your app requests through some kind of proxy

tnmendes commented 3 years ago

@spasea I can see that the responses that you have are from the old firmware when you updated your Tapo firmware you will other response types.

@cjdshaw To get the tapo server you need to run one request to: GET: https://app-server.iot.i.tplinknbu.com/v1/server-info

cjdshaw commented 3 years ago

Thanks guys, but I feel like I'm being stupid here

@tnmendes: I've got the endpoints from that URL { "appServerUrl": "https://euw1-app-server.iot.i.tplinknbu.com", "cloudGatewayUrl": "euw1-app-cloudgateway.iot.i.tplinknbu.com", "securityServerUrl": "https://euw1-security.iot.i.tplinknbu.com" }

but any POST I send to any of them comes back 404 or empty. Are you using the token from the Kasa login, or do I need to do a separate auth for Tapo?

I've tried going through a proxy, but the app just stops working. I'm guessing that it uses certificate pinning so doesn't like the substituted certificate. I can see the hosts it's trying to reach, but not the full path or the request data

Any tips you can give me to go further would be much appreciated

If it's useful to anyone, I've attached my Python script that I use to control / query my Kasa devices. I'd like to update it to support Tapo too

kasa_control.py.zip

adumont commented 3 years ago

Hi, to try and bypass SSL Pinning, you can try the Frida/Objection method, I used and documented a bit here in this repo:

https://github.com/adumont/simyo_mqtt

BTW Frida is also great for inspection and could maybe reveal all the API Calls made by the app. It might be a good thing to investigate a proper javascript to reveal only the relevant calls to the API that is of interest here.

El sáb., 9 ene. 2021 16:21, cjdshaw notifications@github.com escribió:

Thanks guys, but I feel like I'm being stupid here

@tnmendes https://github.com/tnmendes: I've got the endpoints from that URL { "appServerUrl": "https://euw1-app-server.iot.i.tplinknbu.com", "cloudGatewayUrl": "euw1-app-cloudgateway.iot.i.tplinknbu.com", "securityServerUrl": "https://euw1-security.iot.i.tplinknbu.com" }

but any POST I send to any of them comes back 404 or empty. Are you using the token from the Kasa login, or do I need to do a separate auth for Tapo?

I've tried going through a proxy, but the app just stops working. I'm guessing that it uses certificate pinning so doesn't like the substituted certificate. I can see the hosts it's trying to reach, but not the full path or the request data

Any tips you can give me to go further would be much appreciated

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/adumont/tplink-cloud-api/issues/42#issuecomment-757308620, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACRLWWVUYJF7CHDHXOV66TSZBX6BANCNFSM4TU3N5YA .

cjdshaw commented 3 years ago

@adumont Thanks. Time for me to jailbreak one of my iOS devices, I guess!

spasea commented 3 years ago

@cjdshaw if you need to just trace api requests - you can use some kind of solution like charles. As for me - it's easier than to do a jailbreak 🙂 You can install certificate on the device and trace ssl connection as well (I did it with my android, but it's also possible to install cert on ios device). Also you can map remote ips to your local ones (in case you need it)

cjdshaw commented 3 years ago

@spasea Charles works for local calls, but the Tapo and Kasa apps both seem to use certificate pinning for cloud calls. That means they check the certificate they get against one stored in the app package. Since the Charles certificate doesn't match, they refuse to communicate. As @adumont mentioned, you have to use Frida/Objection to bypass this, which needs a jailbreak.

If you've got a simpler way to do this without jailbreaking, I'd love to hear about it

spasea commented 3 years ago

@cjdshaw I think I didn't quite get your point. If you want - you can explain your case in more details. Mine was about request tracing and then using them in your own app, f.ex. do a trace to change socket state and then use the same api endpoint to change the state by your own. To do such a tracing - you need just to install Charles cert on your device (at least this worked for me with android Tapo app).

cjdshaw commented 3 years ago

@spasea That’s exactly what I’m trying to do, using cloud endpoints, not local network communication though. I’ve installed the Charles certificate and I can inspect https browser traffic, so everything is working as it should, but the Kasa and Tapo apps don’t work while SSL proxying is enabled. Interesting that they work OK on Android. Are you using an older OS or app version? I’ll see if I can borrow an Android device and try it out

adumont commented 3 years ago

AFAIK Frida doesn't require rooting your phone on Android. Don't know about the equivalence on iPhone though.

El dom., 10 ene. 2021 21:12, cjdshaw notifications@github.com escribió:

@spasea https://github.com/spasea That’s exactly what I’m trying to do, using cloud endpoints, not local network communication though. I’ve installed the Charles certificate and I can inspect https browser traffic, so everything is working as it should, but the Kasa and Tapo apps don’t work while SSL proxying is enabled. Interesting that they work OK on Android. Are you using an older OS or app version? I’ll see if I can borrow an Android device and try it out

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/adumont/tplink-cloud-api/issues/42#issuecomment-757536179, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACRLWTSB76DVUMR2DHJ2M3SZICZJANCNFSM4TU3N5YA .

cjdshaw commented 3 years ago

Thanks guys. I remembered I had an old Kindle Fire, so I set that up with the Charles proxy and certificate. The Tapo app works fine through the proxy but Kasa still doesn't strangely. I've made a lot of progress with API calls. Updated script attached, if anyone's interested kasa_control_wip.py.zip

jkscx commented 1 year ago

Sorry for resurrecting such an old thread, but did anyone maybe figure out the request structure (for the P100 or similar)?