-
-
Notifications
You must be signed in to change notification settings - Fork 221
Add support for the protocol used by TAPO devices and some newer KASA devices. #552
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really cool, great work @sdb9696! Just wanted to give some quick feedback.
- We should find a nice level of abstraction for tapo devices in general, I ordered a test bulb to help with testing and dev but I'm not going to have much time to tinker until holidays.
- I am wondering how much of this is similar to the klap protocol, i.e., should it make sense to merge them or at least find a way to share some code?
- I presume some of the code is sourced from other projects, are there license incompatibilities?
Yes I was thinking the same. However I wanted to keep this PR as close to your initial #499 as possible so we didn't start off with a giant PR.
There is some overlap, particularly around the retry logic which could be any httpx connection. Again as above I wanted to keep this PR as simple as possible. My suggestion would be to get this working for the Kasa EP25 and a TAPO plug, and then do some refactoring and code re-use in a separate PR. I'm happy to do it the other way round if you want but I thought it would be easier for you to keep things ticking along if you have less to review each time.
Some of the code, i.e. the Cipher, KeyPair and the SnowflakeId came from https://github.com/petretiandrea/plugp100 which seems to have the same GNU GPL 3 license as this library so I don't think there are any incompatibilities. Let me know if you agree. Anyway, let me know how you want to proceed, i.e. with incremental PRs or incremental commits to this PR. |
So I don't have a clear opinion on this. What I was thinking was that it would be great to have a base class straight from the beginning, as that will likely happen in the near future anyway and we know that there exists common functionalities among the devices. Another thing that caught my mind was that maybe it's also a good idea to contain the tapo functionality inside its own package (e.g., inside
Sounds reasonable to me, maybe some parts of the common functionalities can be refactored to the protocol base class to avoid inconsistencies among protocol handling, but that can wait for now.
Yupp, that's fine. Please add a docstring note with a link to the plugp100 repository and mention the compatible, I think that should be good enough :-) |
On another note, maybe the protocol itself should just be renamed and remain in the base package? Given it's not just used for tapo devices, but as an transport & encryption layer for the newer kasa-branded, too. |
|
||
def _md5(payload: bytes) -> bytes: | ||
digest = hashes.Hash(hashes.MD5()) # noqa: S303 | ||
digest.update(payload) |
Check failure
Code scanning / CodeQL
Use of a broken or weak cryptographic hashing algorithm on sensitive data
|
||
def _sha1(payload: bytes) -> str: | ||
sha1_algo = hashlib.sha1() # noqa: S324 | ||
sha1_algo.update(payload) |
Check failure
Code scanning / CodeQL
Use of a broken or weak cryptographic hashing algorithm on sensitive data
@staticmethod | ||
def create_key_pair(key_size: int = 1024): | ||
"""Create a key pair.""" | ||
private_key = rsa.generate_private_key(public_exponent=65537, key_size=key_size) |
Check failure
Code scanning / CodeQL
Use of weak cryptographic key
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #552 +/- ##
==========================================
- Coverage 82.29% 75.84% -6.45%
==========================================
Files 30 33 +3
Lines 2468 2861 +393
Branches 694 747 +53
==========================================
+ Hits 2031 2170 +139
- Misses 379 634 +255
+ Partials 58 57 -1 ☔ View full report in Codecov by Sentry. |
Ok that is done. Base class of TapoDevice(SmartDevice) and TapoPlug derives from TapoDevice (not SmartPlug)
That's done
That's done @ezekieldas could you please check this still works with your EP25? |
f5e320d
to
d5200a7
Compare
This looks fantastic: https://pastebin.com/xRAvpT9u Perhaps non-issue but there is that |
I have several of these new EP25 plugs and can verify that this at least appears to be working:
I am getting a similar ValueError to @ezekieldas at the end of output. Happy to help test, debug, etc. (and send one or two devices to devs for testing. If they don't work with Home Assistant, they are useless to me) |
d5200a7
to
9f5580b
Compare
The ValueError should be fixed if you take the latest version of this PR updated just now |
Yes, so I did another checkout of pull552 and this did correct the
|
I'm going to order a device to have something to test with. Any idea if the P125M will work even though it supports matter? I can't see to find any of them that don't support matter for sale and will ship to Hawaii |
I haven't used or researched these, nor am I familiar with matter. However kp125m is listed on the integrations page. See the comment: supported via Matter, but without energy monitoring features |
I’m not sure I’m afraid. From looking at decompiled Kasa & TAPO .apk I’d say they support both but it’s difficult to be sure. I guess the worst case is we end up with a Matter protocol ;) |
I ordered the EP25 and the kp125m I figure one of them will be useful for testing |
To my understanding, based on some issue comments), the matter-based devices are using the "tapo" protocol (unsure if it's just the transport or also for the command set) as a secondary communications protocol. The emeter features do not work over the matter at the moment, as I think only the recently announced upcoming 1.2 (or 1.3?) has support for such. For EP25, it seems that the new hw version (v4?) is the one that has moved to use the AES encryption, and I'm quite confident others will follow as it just makes sense :-) edit: KP125M seems to use KLAP & tapo commands as per #450 (comment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I received my test bulb today and my pending deadline was postponed a bit, so I had some time to play around with it :-)
Here are some comments, I'll create a draft PR based on this PR that adds support for tapo bulbs. Some notes based on my experiments:
- Adding support for the bulbs felt really easy, I think the effort put into building a good foundation and abstractions were useful! :-)
get_<x>_info
andset_<x>_info
come in pairs, so whenget_device_info
report on brightness, it can be set usingset_device_info
much likedevice_on
.- hue, saturation and brightness are stored in separate fields, so I suppose multi assignments are possible. I haven't yet tested this out, but will do so prior creating the PR.
- Some communications feel rather sluggish, due to multiple queries (device state, then the emeter & the usage). Maybe these could be condensed into a single request? Just a thought..
sdb9696#14 adds support for bulbs. Maybe it would make more sense to base it on top of python-kasa master instead of the branch for the PR at hand to keep the merges small, but github ui's diff view makes it easier to see how few changes were required for basic functionalities :-) |
dbe58bb
to
1008bf9
Compare
Unbelievably, overnight my Tapo P110 updated it's firmware to the KLAP encryption. It's now running sw_version 1.3.0 Build 230905 Rel.152200.
As a result I set to looking at what is needed to support this configuration. I've created a draft PR to support TAPO/KLAP, but I don't know if I've broken the AES transport in the process. I no longer have a device with this configuration :(. @ezekieldas would you mind testing your EP25 with this new PR to see if it still works with your device. @rytilahti there are more comments in the other PR regarding the approach. I've also addressed all your previous review comments in this PR. |
Here are the results from #557: https://pastebin.com/XPpDRS3e It ends with an Just to be certain, I compared same args/creds used in this test with the previous test on #552, and that remains successful. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind adding some tests to make it easier to review the code?
Also, should this get merged before it makes sense to review #557?
self._energy = await self.protocol.query("get_energy_usage") | ||
self._emeter = await self.protocol.query("get_current_power") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bulb seems to support these commands, too, but I'm not sure if we can detect the availability using component_nego
or some other way.
Here's the response for the from the bulb (kasa -d --type tapobulb --username $KASA_TAPO_EMAIL --password $KASA_TAPO_PASSWORD --host 192.168.xx.xx raw-command "" component_nego
):
<< {'component_list': [{'id': 'device', 'ver_code': 2},
{'id': 'firmware', 'ver_code': 2},
{'id': 'quick_setup', 'ver_code': 3},
{'id': 'inherit', 'ver_code': 1},
{'id': 'time', 'ver_code': 1},
{'id': 'wireless', 'ver_code': 1},
{'id': 'schedule', 'ver_code': 2},
{'id': 'countdown', 'ver_code': 2},
{'id': 'antitheft', 'ver_code': 1},
{'id': 'account', 'ver_code': 1},
{'id': 'synchronize', 'ver_code': 1},
{'id': 'sunrise_sunset', 'ver_code': 1},
{'id': 'cloud_connect', 'ver_code': 1},
{'id': 'default_states', 'ver_code': 1},
{'id': 'preset', 'ver_code': 1},
{'id': 'brightness', 'ver_code': 1},
{'id': 'color', 'ver_code': 1},
{'id': 'color_temperature', 'ver_code': 1},
{'id': 'auto_light', 'ver_code': 1},
{'id': 'on_off_gradually', 'ver_code': 1},
{'id': 'device_local_time', 'ver_code': 1},
{'id': 'light_effect', 'ver_code': 1},
{'id': 'iot_cloud', 'ver_code': 1},
{'id': 'bulb_quick_control', 'ver_code': 1}]}
{"component_list": }
I updated the list to the draft bulb PR, so it's easily available.
Please add a debug output for the query, that'll make it easier to debug issues when a query is failing :-)
|
Hi @ezekieldas. I think I've fixed it, could you try again? |
It definitely looks fixed! https://pastebin.com/66Z1XGR5 I do a quick scan (human, me) of the output each time, and here I see the val for ...but other than that, it looks good! |
I've just figured out how to do multiple requests in one go. I'll add support for this in a later PR if that's ok? |
That's fine, let's get preliminary support in and we can then iterate and optimize 👍 |
Thank you very much! |
The trouble is I can no longer test this PR with a device myself because my P110 upgraded to KLAP overnight. Also the changes in #557 are going to make it much easier to write the FakeTransport for testing the TAPO protocol and test using the "new" fixtures with TAPO responses. I don't suppose we could hold off on the tests until #557? It will save me a lot of time and tests is my number 1 priority at the moment (as you may have guessed from #556) |
Sounds reasonable! I'll go through this one later tonight and see if there is something that should be handled before merging this. But I think in the end we will just merge this as is and iterate on later PRs 👍 |
@sdb9696 could you update the title and the description to be more descriptive? Doesn't need to be anything fancy, but given the size and the importance of this change, it would be great to have descriptive ones for anyone reading the changelogs/commit logs. I will now check if there's something that should be changed prior the merge. |
43f5b8e
to
3964415
Compare
3964415
to
24586de
Compare
24586de
to
94981d1
Compare
Now updated with changes or replies. N.B. I have squashed all the commits except the latest to make rebasing #557 on top of this PR easier. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to go, thanks @sdb9696! 💯
Great, thanks @rytilahti! Onto #557 :) |
Related to #499 and #548