Add device fixture for P316M(US) (#1568)
Some checks failed
CI / Perform linting checks (3.13) (push) Has been cancelled
CodeQL checks / Analyze (python) (push) Has been cancelled
CI / Python 3.11 on macos-latest (push) Has been cancelled
CI / Python 3.12 on macos-latest (push) Has been cancelled
CI / Python 3.13 on macos-latest (push) Has been cancelled
CI / Python 3.11 on ubuntu-latest (push) Has been cancelled
CI / Python 3.12 on ubuntu-latest (push) Has been cancelled
CI / Python 3.13 on ubuntu-latest (push) Has been cancelled
CI / Python 3.11 on windows-latest (push) Has been cancelled
CI / Python 3.12 on windows-latest (push) Has been cancelled
CI / Python 3.13 on windows-latest (push) Has been cancelled
Stale / stale (push) Has been cancelled

Adds device fixture and updates powerprotection module to accept the changed enabled key.
---------

Co-authored-by: komodo <komodo@komo.do>
Co-authored-by: Teemu Rytilahti <tpr@iki.fi>
This commit is contained in:
Giovanni
2025-08-30 10:42:53 -04:00
committed by GitHub
parent 08e7ab5120
commit 2b881cfd7b
6 changed files with 3524 additions and 24 deletions

View File

@@ -197,7 +197,7 @@ The following devices have been tested and confirmed as working. If your device
### Supported Tapo[^1] devices
- **Plugs**: P100, P110, P110M, P115, P125M, P135, TP10, TP15
- **Power Strips**: P210M, P300, P304M, P306, TP25
- **Power Strips**: P210M, P300, P304M, P306, P316M, TP25
- **Wall Switches**: S210, S220, S500, S500D, S505, S505D
- **Bulbs**: L510B, L510E, L530B, L530E, L535E, L630
- **Light Strips**: L900-10, L900-5, L920-5, L930-5

View File

@@ -228,6 +228,8 @@ All Tapo devices require authentication.<br>Hub-Connected Devices may work acros
- Hardware: 1.0 (UK) / Firmware: 1.0.3
- **P306**
- Hardware: 1.0 (US) / Firmware: 1.1.2
- **P316M**
- Hardware: 1.6 (US) / Firmware: 1.0.5
- **TP25**
- Hardware: 1.0 (US) / Firmware: 1.0.2

View File

@@ -57,7 +57,9 @@ class PowerProtection(SmartModule):
@property
def enabled(self) -> bool:
"""Return True if child protection is enabled."""
return self.data["get_protection_power"]["enabled"]
settings = self.data["get_protection_power"]
enabled_key = next(k for k in settings if "enabled" in k)
return settings[enabled_key]
async def set_enabled(self, enabled: bool, *, threshold: int | None = None) -> dict:
"""Set power protection enabled.
@@ -73,7 +75,10 @@ class PowerProtection(SmartModule):
"Threshold out of range: %s (%s)", threshold, self.protection_threshold
)
params = {**self.data["get_protection_power"], "enabled": enabled}
enabled_key = next(
k for k in self.data["get_protection_power"] if "enabled" in k
)
params = {**self.data["get_protection_power"], enabled_key: enabled}
if threshold is not None:
params["protection_power"] = threshold
return await self.call("set_protection_power", params)

View File

@@ -112,7 +112,7 @@ SWITCHES_SMART = {
}
SWITCHES = {*SWITCHES_IOT, *SWITCHES_SMART}
STRIPS_IOT = {"HS107", "HS300", "KP303", "KP200", "KP400", "EP40"}
STRIPS_SMART = {"P300", "P304M", "TP25", "EP40M", "P210M", "P306"}
STRIPS_SMART = {"P300", "P304M", "TP25", "EP40M", "P210M", "P306", "P316M"}
STRIPS = {*STRIPS_IOT, *STRIPS_SMART}
DIMMERS_IOT = {"ES20M", "HS220", "KS220", "KS220M", "KS230", "KP405"}

File diff suppressed because it is too large Load Diff

View File

@@ -48,33 +48,40 @@ async def test_set_enable(dev: SmartDevice, mocker: MockerFixture):
# Simple enable with an existing threshold
call_spy = mocker.spy(powerprot, "call")
await powerprot.set_enabled(True)
params = {
"enabled": True,
"protection_power": mocker.ANY,
}
call_spy.assert_called_with("set_protection_power", params)
args, kwargs = call_spy.call_args
method, params = args
assert method == "set_protection_power"
enabled_key = next(
k for k in powerprot.data["get_protection_power"] if "enabled" in k
)
assert params[enabled_key] is True
assert params["protection_power"] is not None
# Enable with no threshold param when 0
call_spy.reset_mock()
await powerprot.set_protection_threshold(0)
await device.update()
await powerprot.set_enabled(True)
params = {
"enabled": True,
"protection_power": int(powerprot._max_power / 2),
}
call_spy.assert_called_with("set_protection_power", params)
args, kwargs = call_spy.call_args
method, params = args
assert method == "set_protection_power"
assert "enabled" in params or "protection_enabled" in params
assert params["protection_power"] == int(powerprot._max_power / 2)
# Enable false should not update the threshold
call_spy.reset_mock()
await powerprot.set_protection_threshold(0)
await device.update()
await powerprot.set_enabled(False)
params = {
"enabled": False,
"protection_power": 0,
}
call_spy.assert_called_with("set_protection_power", params)
args, kwargs = call_spy.call_args
method, params = args
assert method == "set_protection_power"
assert "enabled" in params or "protection_enabled" in params
assert params["protection_power"] == 0
finally:
await powerprot.set_enabled(original_enabled, threshold=original_threshold)
@@ -88,11 +95,12 @@ async def test_set_threshold(dev: SmartDevice, mocker: MockerFixture):
call_spy = mocker.spy(powerprot, "call")
await powerprot.set_protection_threshold(123)
params = {
"enabled": mocker.ANY,
"protection_power": 123,
}
call_spy.assert_called_with("set_protection_power", params)
args, kwargs = call_spy.call_args
method, params = args
assert method == "set_protection_power"
assert "enabled" in params or "protection_enabled" in params
assert params["protection_power"] == 123
with pytest.raises(ValueError, match="Threshold out of range"):
await powerprot.set_protection_threshold(-10)