Skip to content

Conversation

@TheLinuxGuy
Copy link
Contributor

Add P316M support to python-kasa.

komodo added 3 commits July 23, 2025 22:43
…ed keys

The P316M device uses 'protection_enabled' instead of 'enabled' in the
protection power configuration. Update tests to check which key is used
by each device and assert the correct parameters in test calls.
@codecov
Copy link

codecov bot commented Jul 24, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.66%. Comparing base (e21ab90) to head (a79f27a).
⚠️ Report is 11 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1561   +/-   ##
=======================================
  Coverage   92.66%   92.66%           
=======================================
  Files         150      150           
  Lines        9538     9544    +6     
  Branches      974      976    +2     
=======================================
+ Hits         8838     8844    +6     
  Misses        499      499           
  Partials      201      201           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@TheLinuxGuy
Copy link
Contributor Author

I'm a bit stuck and could use some guidance.

Shouldn't this device report its power emeter metrics via CLI? I have tried both these commands and they seem to fail. I don't know what needs to be changed.

uv run kasa --username x --password y --host 192.168.66.240 --debug energy

Error Device has no energy module.

uv run kasa --username x --password y --host 192.168.66.240 --debug usage

Error KeyError: 'usage'
kasa-energy.txt
kasa-usage.txt

energy module to avoid KeyError.
@TheLinuxGuy
Copy link
Contributor Author

TheLinuxGuy commented Jul 24, 2025

While I think I may have found and fixed the bug about energy - I don't think its the correct fix... because this power strip has 6 outlets with energy information. Which function is the correct one for hardware that has many children of energy?

root@kasapi:~/try2/python-kasa# uv run kasa --username xx --password x --host 192.168.66.240 energy
Discovering device 192.168.66.240 for 10 seconds
== Energy ==
Current: 0.0 A
Voltage: 122.359 V
Power: 0.0 W
Total consumption: None kWh
Today: 0.0 kWh
This month: 0.0 kWh

komodo added 2 commits July 23, 2025 23:45
Use a single `if` statement instead of nested `if` statements
@TheLinuxGuy
Copy link
Contributor Author

@rytilahti Hi I know you are busy, do you think you could help share a few pointers on what code may need to be changed to make this device work?

My PR has the fixture files, but IOT powerstrip which has e-meter is not reporting Energy() and usage of each independent power outlet of the powerstrip. I believe this is a new function that may need to be added, perhaps I am wrong and this exists but I do not have any older allegedly supported HS300 power strip to see how it reports emeter data.

Copy link
Member

@rytilahti rytilahti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, @TheLinuxGuy! I added some comments inline, but it is generally looking good. I would suggest that we try to keep this PR as minimum (as it's about adding a fixture) & tackle other issues (like the cli emeter support) in separate PRs.

"""Return True if child protection is enabled."""
return self.data["get_protection_power"]["enabled"]
gp = self.data["get_protection_power"]
return gp.get("enabled") or gp.get("protection_enabled")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return gp.get("enabled") or gp.get("protection_enabled")
return gp.get("enabled", gp.get("protection_enabled"))

Comment on lines 77 to +81
params = {**self.data["get_protection_power"], "enabled": enabled}
# If "enabled" is not used by the device, use "protection_enabled"
if "protection_enabled" in self.data["get_protection_power"]:
params["protection_enabled"] = enabled
params.pop("enabled", None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
params = {**self.data["get_protection_power"], "enabled": enabled}
# If "enabled" is not used by the device, use "protection_enabled"
if "protection_enabled" in self.data["get_protection_power"]:
params["protection_enabled"] = enabled
params.pop("enabled", None)
enabled_key = next(k for k in self.data["get_protection_power"].keys() if "enabled" in k)
params = {**self.data["get_protection_power"], enabled_key: enabled}

How about something like this?

if "protection_enabled" in protection_data:
params = {
"protection_enabled": True,
"protection_power": mocker.ANY,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd do similar trick here as above in the implementation to make it cleaner.

Comment on lines +74 to +82
if "protection_enabled" in protection_data:
params = {
"protection_enabled": True,
"protection_power": int(powerprot._max_power / 2),
}
else:
params = {
"enabled": True,
"protection_power": int(powerprot._max_power / 2),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment above about extracting the key & re-using it to avoid branching here and below.

Comment on lines 166 to 173
# Energy module is not supported on P304M parent device
# P316M powerstrip does not have 'device_on' key in sys_info.
if (
"device_on" not in self._device.sys_info
and self._device.sys_info.get("model") == "P316M"
):
return True
return "device_on" in self._device.sys_info
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this check is only done to avoid initializing energy module for the main device on P304M as it only reports this information on the child sockets. I think this was an easy solution as the main device cannot be switched on and off, but this check should to my understanding also work for your P316M.

Maybe it's just the cli that needs adjustment for devices that have individual sockets with emeter?
In any case, I would suggest that we get this PR first merged without changes to emeter & tackle that issue in a separate PR.

@rytilahti
Copy link
Member

My PR has the fixture files, but IOT powerstrip which has e-meter is not reporting Energy() and usage of each independent power outlet of the powerstrip. I believe this is a new function that may need to be added, perhaps I am wrong and this exists but I do not have any older allegedly supported HS300 power strip to see how it reports emeter data.

IOT powerstrips are structured very differently, so it does not make much sense to take example for them. The emeter support for devices like P304M and P316M should already be there (using the energy_monitoring component), but the cli tool may need some adjustments to expose this information nicely.

If you execute kasa on the device without a command, does it print the device state for the child sockets? Is the emeter information also shown there?

@rytilahti rytilahti added the new device New device supported due to fixture being added label Aug 10, 2025
@rytilahti rytilahti changed the title Update documentation and add new device fixture for P316M(US) Add device fixture for P316M(US) Aug 10, 2025
@TheLinuxGuy
Copy link
Contributor Author

New PR created as requested, with only the fixtures. #1568

@github-actions
Copy link

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
If you are the author of this PR, please leave a comment if you want to keep it open. Also, please rebase your PR onto the latest dev branch to ensure that it's up to date with the latest changes.
Thank you for your contribution!

@github-actions github-actions bot added stale and removed stale labels Nov 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new device New device supported due to fixture being added

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants