Use pan/tilt function for TP-Link Tapo C200 from Home assistant?

So, here we go…

This is write-up what actually you can do with a Tapo C200 camera without the the Tapo app, and someone might want to carry on the research and make a functional integration of it.

A few days ago, I’ve bought a Tapo C200, brilliant little device for the price, but I couldn’t believe that it cannot be controlled under HA, I’ve searched a lot and couldn’t find any information about any API what the device would use, but actually it has one.
I ran into an article from NCC Group, about a research on multiple IP cameras, including the Tapo C200 as well. They have found a vulnerability (Heartbleed) in the implementation of the device which has been fixed since that, thank you for those good people there. But that is not really the point here, instead the article contained some documentation how they managed to get access to the Tapo C200.

Here is the article if you want to read it, and make sure you update your firmware!

So, they introduced a method called stok method. Once the user authenticated towards the camera on https (port 443), the camera gives back a stok value, what can be used further on to interact with the camera’s API. Nicely, everything is JSON formatted, and easy to read and handle.

The method to get the stok value is to do a POST to the camera through https as follows:

POST / HTTP/1.1
Host: CAM_IP
Referer: https://CAM_IP:443
Accept: application/json
Accept-Encoding: gzip, deflate
User-Agent: Tapo CameraClient Android
Connection: close
requestByApp: true
Content-Type: application/json; charset=UTF-8

{
    "method": "login",
    "params": {
        "hashed": true,
        "password": "MD5 HASH of the password, with ALL Capital Letters",
        "username": "admin"
    }
}

Here to note the password is the password, what you have registered your user before in the Tapo app. The password has to be MD5 hashed, and capitalized to make it work. (I used Postman to test all of these.)

The result will be something like this:


{

    "error_code": 0,

    "result": {

        "stok": "023c3bb0bff01dd799c1f4c7f406d9f5",

        "user_group": "root"

    }

}

The stok value changes time to time, it has about 30-60 minutes expiration time. So it has to be renewed.

How to use the stok value, do another POST:

POST /stok=023c3bb0bff01dd799c1f4c7f406d9f5/ds HTTP/1.1
Host: CAM_IP
Referer: https://CAM_IP:443
Accept: application/json
Accept-Encoding: gzip, deflate
User-Agent: Tapo CameraClient Android
Connection: close
requestByApp: true
Content-Type: application/json; charset=UTF-8

{"method":"get", "function":{"name": ['module_spec']}}

This time the address will have /stok=023c3bb0bff01dd799c1f4c7f406d9f5/ds added to it. Everything else goes into the body of the POST.

The original article list some nice commands how to rotate the camera, turn on and off the mask, and some nasty stuff as well, but not so many commands. So I started a hunt for more commands, and found a small repo on GitHub, which listed a few more:

Not so much, but a good start. It was designed for some TPLink device 2 and a half year ago. Indeed it uses a different method for the login, but again uses the stok value.

I’ve played around with it, and all works nicely, the camera can be rotated and so on. But I couldn’t believe that that must be it, so dug deeper on GitHub, and found another repo, which should be a controller for a Mercury camera.
Oh, this is a big hit, it has plenty more data to go further:

The original repo:

Some further developed version for Mercury cameras and HA:

All great work, but mostly based on this research:

All the Mercury IPC Control uses a rsa encryption method for logging in and getting the stok value, what I haven’t tested, probably it would work as well, as all indication suggest the same API on the Tapo C200 as on the Mercury camera.

Most of the commands listed in these repos are working well, except the greeter one.

Unfortunately, I couldn’t find the following yet:
-Get motion events from the camera, either by polling or changing the push address.
-Get a still image from the camera (it should be possible as the Tapo app capable to make images)
-Be able to change the Wifi network details, AP and Password
-Get a full list of methods, functions, parameters, tables and names of the API.

If anyone has the knowledge to do some more research maybe by WireShark, to capture some further commands, or have any idea what API is in use with these cameras and knows a documentation somewhere hidden in a dark corner of the web, then please don’t hesitate to post here.

I have a belief that the same method should work with the Tapo C100 cameras as well, and maybe with the Tapo P100 plugs too. Just need to dig further into the API to get the right commands.

I really hope this will give some traction to get a working integration for these little dirt cheap superb cameras.

I have to say thank you for the initial research on the Tapo C200 to Dale Pavey (@Dpavey) from NCC Group, and @likaci for the research on the Mercury camera. And @ttimasdf for the additional work on the Mercury camera. Thanks for all the great work!

Just to get a notification, I tag a few people from the topic, who might be interested as well:

@epeome5, @traverst, @krash, @martinwahlstrom, @zbuh, @2t0m, @tavares

6 Likes

This is so AWESOME @GSzabados ! Thank you!

I have created a pip module that makes control a lot easier and implemented all the functions I could find or guess.

I would really like to discover a way how to delete presets as that is the only preset-specific thing missing.

I will soon start work on Home Assistant addon!

2 Likes

I have seen one place where there was a reference how to delete presets as well. Maybe the last from @ttimasdf. Have a look at that.

Indeed it is there:

{"method":"do","preset":{"remove_preset":{"id":["CHANGEME"]}}}

But I haven’t tried this, just to create one.

1 Like

Priceless!
Amazing work.

Home Assistant custom component is available here: https://github.com/JurajNyiri/HomeAssistant-Tapo-Control

Please continue discussion about it at community forum Tapo: Cameras Control.

Right now it allows to move ptz to prefixes created through apps and allows for multiple cameras.
It also creates entities having base information in attributes.

A lot of new features coming soon!

8 Likes

I am glad that my research is being put to good use in the home automation area. What are you missing in terms of API? I can look at my original code/research notes and try to fill in the gaps.

2 Likes

This is very interesting, thanks for sharing.
Does the tapo camera use Bluetooth?
I’m looking at the Tapo 100 plug and it’s using Bluetooth as a part of the setup process.

Many thanks.

Hi Dale,

What I have had in my mind, is to find some option through the API, to set up the device’s wifi connection without the Tapo app, to ditch that step as well, if possible.
Secondly, I couldn’t find any way to get the motion detection status from the camera. Or to find what the address the device pushes the status message, and is it possible to change that. I hope, there is some way to get that pushed to HA and not to the TP-Link cloud, or to do polling on the status, as some other integrations do it (ie.: Foscam).

Otherwise, the Mercury cameras API showed that this little camera capable even to do motion tracking as well, what I haven’t seen in the Tapo App as a function, and do some other enhancement stuff too. (I haven’t tried that…)

{"method":"set","target_track":{"target_track_info":{"enabled":"on"}}}
{"method":"set","target_track":{"target_track_info":{"enabled":"off"}}}

If you have some list of the Error codes, that would be helpful as well.

I think, that the API commands what you have found in the app, might be a bit different from the ones from the Mercury cameras, as they use the generic get, set, do methods but not the multipleRequest ones. Maybe it is just a shortcut built in to the API.

If you are planning to continue the research on other cameras, I would strongly advise to look at Wyze (Xiaomi) and Blink cameras as well. They are quite cheap, and many people uses them. There is even a dedicated hack for Wyze/Xiaomi Dafang cameras to replace the firmware.

Thank you very much for your research, it is really appreciated to kickstart this integration.

2 Likes

No, it is not using Bluetooth, it is pure Wifi I believe. As the camera creates a wifi hotspot what your phone has to connect to, to be able to set up the wifi connection to the Tp-Link cloud.

Can you try with the plug, that you log in with the stok method and can get the basic information of it?

{"method":"get","device_info":{"name":["basic_info"]}}
{"method":"get","function":{"name":["module_spec"]}}

I forgot to mention the image capture, if you have any reference to that. I just guess that it might have an option, as it is quite standard, but it can be that the app does only a screenshot from the RTSP feed.

Hey @Dpavey !

If you found some time and found out how to do things below it would be really awesome and I think many people would be using these features.

  • Subscribtion to events (ie. motion tracking) or maybe just a pull on schedule
  • A way to download photos / videos, app can do this so it should be possible through API. Not necessarily for HASS, but I would love to have a script which downloads saved videos from sd card and backs them up to NAS/Cloud.
  • Biggest wish of everyone is of course API documentation or a list of functions/parameters but I think that is really hard to get :slight_smile:

On another note, I was trying to do research on my own when I bought the camera back in early 2020 but the communication was encrypted and any attempt to decode it failed (it also uses cert binding and I could not remove that). I tried to decompile the app and remove the cert pinning but couldn’t find the relevant part of the code and none of the automated ways worked.
Have you only used Heartbleed to discover the communication or did you find also some other ways that we could replicate to figure out more functions? With the patched devices now I think I am not able to use the method you have described.

@GSzabados I have tested tracking yesterday and it works very nicely. I wonder why its not included in the app, maybe it causes some stability issues or they just keep it out on purpose because of the price?

1 Like

Hi @JurajNyiri

If you have a rooted android device and Burp Suit Pro (or a free open source alternatives), you can bypass cert pinning all together. This can be done using Frida to inject the Burp CA into the mobile application and then proxying the mobile device to Burp Suit Pro running on your network. If you have some issues with this, I can try and make a how-to guide.

I think I saw some API calls to pull down schedules, I will double check this for you.

The heartbleed function was just used to implement the attack and take full control of the device from an attacker point of view. Thankfully we got this patched up!

In terms of the RTSP feed, you can create on via the API function I found to create a local account on the device but I have not found a way for it to ignore the signature checks.

For the setting up of the device or changing the Wi-Fi, this again I will need to check to see how it does this!

3 Likes

@Dpavey Thank you for all the information!

I was trying to do this with Fiddler and Frida following more or less this article for Frida part Technique 3 – Frida Hook: https://blog.netspi.com/four-ways-bypass-android-ssl-verification-certificate-pinning/

I was still unsuccessful and traffic was still encoded. I am not sure what the error message was as it was around half a year ago. I was doing this on Tapo: Cameras app.

I might give it another go and try again with the current app version.

When/If you decide to write a guide please let me know!

1 Like

Does the Tapo C310 work with HA and MotionEye, like the C200? Thanks.

Hi, is it possible this, on Camera Tapo c200? Or any other kind of record or snapshot by home assistant.

- action: call-service
          - service: camera.snapshot
          - service_data:
              - entity_id: camera.camera_hd
              - filename: >-
                  /config/tmp/kitchen_{{ now ().year }}_{{ now ().month
                  }}_{{now().day }}_{{ now ().hour }}_{{ now ().minute }}.jpg

Yep:

Make sure you have the path ok. (You have tmp in config and it’s accessible?)

- alias: Cam snapshot
  trigger: <whatever you want>
  action:
    - service: camera.snapshot
      entity_id: camera.camera_hd
      data:
        filename: '/config/tmp/kitchen_{{now().year}}_{{now().month}}_{{now().day}}_{{now().hour}}_{{now().minute}}.jpg'

Martin/

Thank, it is now correct. A have other one question yet. Do you have any idea, how can I connect HA to net shared foldet? I would like save camera.record video to net storage. Thanks

This is possible but is dependent on your environment.

You should search for something like “home assistant mount network storage”.

For example, this or this came up for me.

No plans to make a ptz script for zoneminder? :wink: