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
23221. **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}).
25243. **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
3332Typically, a trait will instantiate a single `DpsDataConverter` for its status class
3433and call `update_from_dps` whenever new data is received from the device stream.
35-
3634"""
3735
3836import dataclasses
3937import logging
4038from collections .abc import Callable
41- from typing import Any
39+ from typing import Any , Generic , TypeVar
4240
4341from roborock .callbacks import CallbackList
44- from roborock .data .b01_q10 .b01_q10_code_mappings import B01_Q10_DP
4542from roborock .data .containers import RoborockBase
4643
44+ TDps = TypeVar ("TDps" , bound = int )
45+
4746
4847class 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