Skip to content

Commit d125afb

Browse files
authored
refactor: centralize trait update listener and dps converter (#820)
1 parent ead2fda commit d125afb

2 files changed

Lines changed: 13 additions & 15 deletions

File tree

roborock/devices/traits/b01/q10/status.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55

66
from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP
77
from roborock.data.b01_q10.b01_q10_containers import Q10Status
8-
9-
from .common import DpsDataConverter, TraitUpdateListener
8+
from roborock.devices.traits.common import DpsDataConverter, TraitUpdateListener
109

1110
_LOGGER = logging.getLogger(__name__)
1211

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
"""Common utilities for Q10 traits.
1+
"""Common utilities for device traits.
22
3-
This module provides infrastructure for mapping Roborock Data Points (DPS) to
4-
Python dataclass fields and handling the lifecycle of data updates from the
5-
device.
3+
This module provides shared infrastructure for mapping Roborock Data Points (DPS) to
4+
Python dataclass fields and handling the lifecycle of data updates from the device.
65
76
### DPS Metadata Annotation
87
@@ -21,7 +20,7 @@ class MyStatus(RoborockBase):
2120
2221
### Update Lifecycle
2322
1. **Raw Data**: The device sends encoded DPS updates over MQTT.
24-
2. **Decoding**: The transport layer decodes these into a dictionary (e.g., `{"101": 80}`).
23+
2. **Decoding**: The transport layer decodes these into a dictionary (e.g., {"101": 80}).
2524
3. **Conversion**: `DpsDataConverter` uses `RoborockBase.convert_dict` to transform
2625
raw values into appropriate Python types (e.g., Enums, ints) based on the
2726
dataclass field types.
@@ -32,18 +31,18 @@ class MyStatus(RoborockBase):
3231
3332
Typically, a trait will instantiate a single `DpsDataConverter` for its status class
3433
and call `update_from_dps` whenever new data is received from the device stream.
35-
3634
"""
3735

3836
import dataclasses
3937
import logging
4038
from collections.abc import Callable
41-
from typing import Any
39+
from typing import Any, Generic, TypeVar
4240

4341
from roborock.callbacks import CallbackList
44-
from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP
4542
from roborock.data.containers import RoborockBase
4643

44+
TDps = TypeVar("TDps", bound=int)
45+
4746

4847
class TraitUpdateListener:
4948
"""Trait update listener.
@@ -71,31 +70,31 @@ def _notify_update(self) -> None:
7170
self._update_callbacks(None)
7271

7372

74-
class DpsDataConverter:
73+
class DpsDataConverter(Generic[TDps]):
7574
"""Utility to handle the transformation and merging of DPS data into models.
7675
7776
This class pre-calculates the mapping between Data Point IDs and dataclass fields
7877
to optimize repeated updates from device streams.
7978
"""
8079

81-
def __init__(self, dps_type_map: dict[B01_Q10_DP, type], dps_field_map: dict[B01_Q10_DP, str]):
80+
def __init__(self, dps_type_map: dict[TDps, type], dps_field_map: dict[TDps, str]):
8281
"""Initialize the converter for a specific RoborockBase-derived class."""
8382
self._dps_type_map = dps_type_map
8483
self._dps_field_map = dps_field_map
8584

8685
@classmethod
8786
def from_dataclass(cls, dataclass_type: type[RoborockBase]):
8887
"""Initialize the converter for a specific RoborockBase-derived class."""
89-
dps_type_map: dict[B01_Q10_DP, type] = {}
90-
dps_field_map: dict[B01_Q10_DP, str] = {}
88+
dps_type_map: dict[TDps, type] = {}
89+
dps_field_map: dict[TDps, str] = {}
9190
for field_obj in dataclasses.fields(dataclass_type):
9291
if field_obj.metadata and "dps" in field_obj.metadata:
9392
dps_id = field_obj.metadata["dps"]
9493
dps_type_map[dps_id] = field_obj.type
9594
dps_field_map[dps_id] = field_obj.name
9695
return cls(dps_type_map, dps_field_map)
9796

98-
def update_from_dps(self, target: RoborockBase, decoded_dps: dict[B01_Q10_DP, Any]) -> bool:
97+
def update_from_dps(self, target: RoborockBase, decoded_dps: dict[TDps, Any]) -> bool:
9998
"""Convert and merge raw DPS data into the target object.
10099
101100
Uses the pre-calculated type mapping to ensure values are converted to the

0 commit comments

Comments
 (0)