8000 Migrate RuleModule to mashumaro (#1283) · ryenitcher/python-kasa@f7778aa · GitHub
[go: up one dir, main page]

Skip to content

Commit f7778aa

Browse files
authored
Migrate RuleModule to mashumaro (python-kasa#1283)
Also fixes a bug whereby multiple queries for the same module would overwrite each other.
1 parent a4258cc commit f7778aa

File tree

4 files changed

+70
-13
lines changed

4 files changed

+70
-13
lines changed

kasa/iot/iotdevice.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,15 @@ async def _modular_update(self, req: dict) -> None:
412412
# every other update will query for them
413413
update: dict = self._last_update.copy() if self._last_update else {}
414414
for response in responses:
415-
update = {**update, **response}
415+
for k, v in response.items():
416+
# The same module could have results in different responses
417+
# i.e. smartlife.iot.common.schedule for Usage and
418+
# Schedule, so need to call update(**v) here. If a module is
419+
# not supported the response
420+
# {'err_code': -1, 'err_msg': 'module not support'}
421+
10000 # become top level key/values of the response so check for dict
422+
if isinstance(v, dict):
423+
update.setdefault(k, {}).update(**v)
416424
self._last_update = update
417425

418426
# IOT modules are added as default but could be unsupported post first update

kasa/iot/modules/rulemodule.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
from __future__ import annotations
44

55
import logging
6+
from dataclasses import dataclass
67
from enum import Enum
78

8-
from pydantic.v1 import BaseModel
9+
from mashumaro import DataClassDictMixin
910

1011
from ..iotmodule import IotModule, merge
1112

@@ -28,26 +29,27 @@ class TimeOption(Enum):
2829
AtSunset = 2
2930

3031

31-
class Rule(BaseModel):
32+
@dataclass
33+
class Rule(DataClassDictMixin):
3234
"""Representation of a rule."""
3335

3436
id: str
3537
name: str
36-
enable: bool
38+
enable: int
3739
wday: list[int]
38-
repeat: bool
40+
repeat: int
3941

4042
# start action
41-
sact: Action | None
42-
stime_opt: TimeOption
43-
smin: int
43+
sact: Action | None = None
44+
stime_opt: TimeOption | None = None
45+
smin: int | None = None
4446

45-
eact: Action | None
46-
etime_opt: TimeOption
47-
emin: int
47+
eact: Action | None = None
48+
etime_opt: TimeOption | None = None
49+
emin: int | None = None
4850

4951
# Only on bulbs
50-
s_light: dict | None
52+
s_light: dict | None = None
5153

5254

5355
_LOGGER = logging.getLogger(__name__)
@@ -66,7 +68,7 @@ def rules(self) -> list[Rule]:
6668
"""Return the list of rules for the service."""
6769
try:
6870
return [
69-
Rule.parse_obj(rule) for rule in self.data["get_rules"]["rule_list"]
71+
Rule.from_dict(rule) for rule in self.data["get_rules"]["rule_list"]
7072
]
7173
except Exception as ex:
7274
_LOGGER.error("Unable to read rule list: %s (data: %s)", ex, self.data)

tests/fakeprotocol_iot.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,34 @@ def success(res):
136136
}
137137
}
138138

139+
SCHEDULE_MODULE = {
140+
"get_next_action": {
141+
"action": 1,
142+
"err_code": 0,
143+
"id": "0794F4729DB271627D1CF35A9A854030",
144+
"schd_time": 68927,
145+
"type": 2,
146+
},
147+
"get_rules": {
148+
"enable": 1,
149+
"err_code": 0,
150+
"rule_list": [
151+
{
152+
"eact": -1,
153+
"enable": 1,
154+
"id": "8AA75A50A8440B17941D192BD9E01FFA",
155+
"name": "name",
156+
"repeat": 1,
157+
"sact": 1,
158+
"smin": 1027,
159+
"soffset": 0,
160+
"stime_opt": 2,
161+
"wday": [1, 1, 1, 1, 1, 1, 1],
162+
},
163+
],
164+
"version": 2,
165+
},
166+
}
139167

140168
AMBIENT_MODULE = {
141169
"get_current_brt": {"value": 26, "err_code": 0},
@@ -450,6 +478,8 @@ def set_time(self, new_state: dict, *args):
450478
"smartlife.iot.PIR": MOTION_MODULE,
451479
"cnCloud": CLOUD_MODULE,
452480
"smartlife.iot.common.cloud": CLOUD_MODULE,
481+
"schedule": SCHEDULE_MODULE,
482+
"smartlife.iot.common.schedule": SCHEDULE_MODULE,
453483
}
454484

455485
async def send(self, request, port=9999):

tests/iot/modules/test_schedule.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import pytest
2+
3+
from kasa import Device, Module
4+
from kasa.iot.modules.rulemodule import Action, TimeOption
5+
6+
from ...device_fixtures import device_iot
7+
8+
9+
@device_iot
10+
def test_schedule(dev: Device, caplog: pytest.LogCaptureFixture):
11+
schedule = dev.modules.get(Module.IotSchedule)
12+
assert schedule
13+
if rules := schedule.rules:
14+
first = rules[0]
15+
assert isinstance(first.sact, Action)
16+
assert isinstance(first.stime_opt, TimeOption)
17+
assert "Unable to read rule list" not in caplog.text

0 commit comments

Comments
 (0)
0