When i control the Tapo Plugs (like P100) i can use KLAP encryption with --credentions-hash , but when i try to access the H100 Hub I have to use AES and --username and --password.
Using credentials-hash gives me:
Raised error: 'utf-8' codec can't decode byte 0xed in position 1: invalid continuation byte
Note:
I used the same credentials hash for the Hub (AES) as I used for the Plug (KLAP) - I already learned that the hashes have to be different, so that is probably related.
My other problem is that I cannot find out the correct credential hash for the hub...
For the Plug i use the following snippet:
device = await Discover.discover_single(
"192.168.1.211",
credentials=Credentials("xxxx", "xxx"),
discovery_timeout=10
)
config = device.config # DeviceConfig.to_dict() can be used to store for later
later_device = await SmartDevice.connect(config=config)
await later_device.update()
print(later_device.credentials_hash)
But for the H100 this code does not work - result:
...
File "C:\Users\ngaer\AppData\Local\Programs\Python\Python311\Lib\site-packages\kasa\discover.py", line 454, in _get_device_instance
raise UnsupportedDeviceException(
kasa.exceptions.UnsupportedDeviceException: Unsupported device 192.168.1.86 of type SMART.TAPOHUB with encrypt_type AES
If you need only the hash and not the rest of the device config, you could try device.credentials_hash. But there's indeed a bug as reconstructing the instance from the device config should work.
Looking at the code, the credentials nor the credentials hash are not actually included, but you need to pass it manually:
Hi @ngaertner it looks like you might be using the 0.6.2.1 version of the library which does not support the SMART.TAPOHUB. You'd need to run the code above from master for it to work with the hub.
Out of interest why are you trying to get the credential_hashes as opposed to just using the username and password?
Yeah, it's a good idea to use hashes for storage and we do this in homeassistant, too. The problem arises when we have two (or more) types of hashes. We could solve this either by:
Adding explicit options (and environment variables) for AES and KLAP, or
Making it possible to pass multiple hashes which are tried until exhausted, or
Going one step further with number two and encoding the type of the hash in the entry.
The first may not work that well in practise, as different klap versions did use different way for hashing. It also clutters the environment, may confuse users, and is a bit complicated to extend when and if new ways for hashing appear.
The second will cause unwanted extra I/O, but be rather easy to implement by allowing passing the --credentials-hash multiple times (and allowing to store them as a list for the environment variable).
The third option is similar to what is used for password hashing of /etc/shadow where the format is something like $<hash type>$<salt>$<hash itself>. This would be an extension to the second one, and probably the best option.
@ngaertner Steven meant that you should try this again with the current master branch. FWIW, the code you gave is working for me and prints out the same hash as kasa --host <addr> -v.
There is a bug in the condition when passing the hash though, and you are forced to define at least --credentials-hash, --encrypt-type and --device-family for it to work. I just confirmed that the hash is working on my H100 with kasa --host 192.168.250.131 --credentials-hash xxx== --encrypt-type AES --login-version 2 --device-family SMART.KASAHUB
If you need only the hash and not the rest of the device config, you could try device.credentials_hash. But there's indeed a bug as reconstructing the instance from the device config should work.
I'm not sure of the bug here as I believe it does work to reconstruct the device from the config. Is there an example I can try?
Looking at the code, the credentials nor the credentials hash are not actually included, but you need to pass it manually:
device.config.to_dict(credentials_hash=device.credentials_hash)
If you provide a credentials_hash the return dict will be saved with the hash, otherwise the clear text credentials will be included in the dict unless exclude_credentials is set to True.
There is a bug in the condition when passing the hash though, and you are forced to define at least --credentials-hash, --encrypt-type and --device-family for it to work. I just confirmed that the hash is working on my H100 with kasa --host 192.168.250.131 --credentials-hash xxx== --encrypt-type AES --login-version 2 --device-family SMART.KASAHUB
I wouldn't call this a bug at the moment because the credentials_hash is dependant on the encryption scheme so these parameters are required for connect. However based on this suggestion:
The third option is similar to what is used for password hashing of /etc/shadow where the format is something like $<hash type>$<salt>$<hash itself>. This would be an extension to the second one, and probably the best option.
This is not that different from storing the dict and then restoring it although it does give an easy way to pass it on the command line. If we think there's a broad use case out there for this behaviour we could extend the cli to support a credentials-hash command that returns a hash with encryption scheme information embedded.
I think i will anyways need to wait for the next stable release - any date for it?
There hasn't been any activity on this issue recently. This issue has been automatically marked as stale because of that. It will be closed if no further activity occurs.
Please make sure to update to the latest python-kasa version and check if that solves the issue.
Thank you for your contributions.
Activity
rytilahti commented on Apr 28, 2024
If you need only the hash and not the rest of the device config, you could try device.credentials_hash. But there's indeed a bug as reconstructing the instance from the device config should work.
Looking at the code, the credentials nor the credentials hash are not actually included, but you need to pass it manually:
I cannot recall the reasoning for this, maybe @sdb9696 has some ideas here :-)
sdb9696 commented on Apr 29, 2024
Hi @ngaertner it looks like you might be using the 0.6.2.1 version of the library which does not support the SMART.TAPOHUB. You'd need to run the code above from master for it to work with the hub.
Out of interest why are you trying to get the credential_hashes as opposed to just using the username and password?
ngaertner commented on May 2, 2024
Hi @sdb9696,
I am confused now - https://github.com/python-kasa/python-kasa says:
I prefer the credentials hash as I dont want to store my TAPO username and password in a script.
rytilahti commented on May 2, 2024
Yeah, it's a good idea to use hashes for storage and we do this in homeassistant, too. The problem arises when we have two (or more) types of hashes. We could solve this either by:
The first may not work that well in practise, as different klap versions did use different way for hashing. It also clutters the environment, may confuse users, and is a bit complicated to extend when and if new ways for hashing appear.
The second will cause unwanted extra I/O, but be rather easy to implement by allowing passing the --credentials-hash multiple times (and allowing to store them as a list for the environment variable).
The third option is similar to what is used for password hashing of /etc/shadow where the format is something like $<hash type>$<salt>$<hash itself>. This would be an extension to the second one, and probably the best option.
@ngaertner Steven meant that you should try this again with the current master branch. FWIW, the code you gave is working for me and prints out the same hash as kasa --host <addr> -v.
There is a bug in the condition when passing the hash though, and you are forced to define at least --credentials-hash, --encrypt-type and --device-family for it to work. I just confirmed that the hash is working on my H100 with kasa --host 192.168.250.131 --credentials-hash xxx== --encrypt-type AES --login-version 2 --device-family SMART.KASAHUB
ngaertner commented on May 2, 2024
I was able to generate an AES credentials-hash for the hub, but only after fixing lots of errors like this:
ModuleNotFoundError: No module named 'pydantic.v1'
-> i had to replace pydantic.v1 by pydantic to get it running.
I think i will anyways need to wait for the next stable release - any date for it?
sdb9696 commented on May 3, 2024
I'm not sure of the bug here as I believe it does work to reconstruct the device from the config. Is there an example I can try?
If you provide a credentials_hash the return dict will be saved with the hash, otherwise the clear text credentials will be included in the dict unless exclude_credentials is set to True.
I wouldn't call this a bug at the moment because the credentials_hash is dependant on the encryption scheme so these parameters are required for connect. However based on this suggestion:
This is not that different from storing the dict and then restoring it although it does give an easy way to pass it on the command line. If we think there's a broad use case out there for this behaviour we could extend the cli to support a credentials-hash command that returns a hash with encryption scheme information embedded.
Not yet but aiming for this month.
github-actions commented on Sep 28, 2024
There hasn't been any activity on this issue recently. This issue has been automatically marked as stale because of that. It will be closed if no further activity occurs.
Please make sure to update to the latest python-kasa version and check if that solves the issue.
Thank you for your contributions.