roborock.devices.traits.v1.clean_summary
1import logging 2 3from roborock.data import CleanRecord, CleanSummaryWithDetail, RoborockBase 4from roborock.devices.traits.v1 import common 5from roborock.exceptions import RoborockParsingException 6from roborock.roborock_typing import RoborockCommand 7from roborock.util import unpack_list 8 9_LOGGER = logging.getLogger(__name__) 10 11 12class CleanSummaryConverter(common.V1TraitDataConverter): 13 """Converter for CleanSummaryWithDetail objects.""" 14 15 def convert(self, response: common.V1ResponseData) -> RoborockBase: 16 """Parse the response from the device into a CleanSummary.""" 17 if isinstance(response, dict): 18 return CleanSummaryWithDetail.from_dict(response) 19 elif isinstance(response, list): 20 clean_time, clean_area, clean_count, records = unpack_list(response, 4) 21 return CleanSummaryWithDetail( 22 clean_time=clean_time, 23 clean_area=clean_area, 24 clean_count=clean_count, 25 records=records, 26 ) 27 elif isinstance(response, int): 28 return CleanSummaryWithDetail(clean_time=response) 29 raise ValueError(f"Unexpected clean summary format: {response!r}") 30 31 32class CleanRecordConverter(common.V1TraitDataConverter): 33 """Convert server responses to a CleanRecord.""" 34 35 def convert(self, response: common.V1ResponseData) -> CleanRecord: 36 """Parse the response from the device into a CleanRecord.""" 37 if isinstance(response, list) and len(response) == 1: 38 response = response[0] 39 if isinstance(response, dict): 40 return CleanRecord.from_dict(response) 41 if isinstance(response, list): 42 if isinstance(response[-1], dict): 43 records = [CleanRecord.from_dict(rec) for rec in response] 44 final_record = records[-1] 45 try: 46 # This code is semi-presumptuous - so it is put in a try finally to be safe. 47 final_record.begin = records[0].begin 48 final_record.begin_datetime = records[0].begin_datetime 49 final_record.start_type = records[0].start_type 50 for rec in records[0:-1]: 51 final_record.duration = (final_record.duration or 0) + (rec.duration or 0) 52 final_record.area = (final_record.area or 0) + (rec.area or 0) 53 final_record.avoid_count = (final_record.avoid_count or 0) + (rec.avoid_count or 0) 54 final_record.wash_count = (final_record.wash_count or 0) + (rec.wash_count or 0) 55 final_record.square_meter_area = (final_record.square_meter_area or 0) + ( 56 rec.square_meter_area or 0 57 ) 58 return final_record 59 except Exception: 60 # Return final record when an exception occurred 61 return final_record 62 # There are still a few unknown variables in this. 63 begin, end, duration, area = unpack_list(response, 4) 64 return CleanRecord(begin=begin, end=end, duration=duration, area=area) 65 raise ValueError(f"Unexpected clean record format: {response!r}") 66 67 68class CleanSummaryTrait(CleanSummaryWithDetail, common.V1TraitMixin): 69 """Trait for managing the clean summary of Roborock devices.""" 70 71 command = RoborockCommand.GET_CLEAN_SUMMARY 72 converter = CleanSummaryConverter() 73 clean_record_converter = CleanRecordConverter() 74 75 async def refresh(self) -> None: 76 """Refresh the clean summary data and last clean record. 77 78 Assumes that the clean summary has already been fetched. 79 """ 80 await super().refresh() 81 if not self.records: 82 _LOGGER.debug("No clean records available in clean summary.") 83 self.last_clean_record = None 84 return 85 last_record_id = self.records[0] 86 self.last_clean_record = await self.get_clean_record(last_record_id) 87 88 async def get_clean_record(self, record_id: int) -> CleanRecord: 89 """Load a specific clean record by ID.""" 90 response = await self.rpc_channel.send_command(RoborockCommand.GET_CLEAN_RECORD, params=[record_id]) 91 try: 92 return self.clean_record_converter.convert(response) 93 except (TypeError, ValueError) as err: 94 raise RoborockParsingException( 95 trait_name=type(self).__name__, 96 command=RoborockCommand.GET_CLEAN_RECORD, 97 payload=response, 98 inner_error=err, 99 ) from err
13class CleanSummaryConverter(common.V1TraitDataConverter): 14 """Converter for CleanSummaryWithDetail objects.""" 15 16 def convert(self, response: common.V1ResponseData) -> RoborockBase: 17 """Parse the response from the device into a CleanSummary.""" 18 if isinstance(response, dict): 19 return CleanSummaryWithDetail.from_dict(response) 20 elif isinstance(response, list): 21 clean_time, clean_area, clean_count, records = unpack_list(response, 4) 22 return CleanSummaryWithDetail( 23 clean_time=clean_time, 24 clean_area=clean_area, 25 clean_count=clean_count, 26 records=records, 27 ) 28 elif isinstance(response, int): 29 return CleanSummaryWithDetail(clean_time=response) 30 raise ValueError(f"Unexpected clean summary format: {response!r}")
Converter for CleanSummaryWithDetail objects.
16 def convert(self, response: common.V1ResponseData) -> RoborockBase: 17 """Parse the response from the device into a CleanSummary.""" 18 if isinstance(response, dict): 19 return CleanSummaryWithDetail.from_dict(response) 20 elif isinstance(response, list): 21 clean_time, clean_area, clean_count, records = unpack_list(response, 4) 22 return CleanSummaryWithDetail( 23 clean_time=clean_time, 24 clean_area=clean_area, 25 clean_count=clean_count, 26 records=records, 27 ) 28 elif isinstance(response, int): 29 return CleanSummaryWithDetail(clean_time=response) 30 raise ValueError(f"Unexpected clean summary format: {response!r}")
Parse the response from the device into a CleanSummary.
33class CleanRecordConverter(common.V1TraitDataConverter): 34 """Convert server responses to a CleanRecord.""" 35 36 def convert(self, response: common.V1ResponseData) -> CleanRecord: 37 """Parse the response from the device into a CleanRecord.""" 38 if isinstance(response, list) and len(response) == 1: 39 response = response[0] 40 if isinstance(response, dict): 41 return CleanRecord.from_dict(response) 42 if isinstance(response, list): 43 if isinstance(response[-1], dict): 44 records = [CleanRecord.from_dict(rec) for rec in response] 45 final_record = records[-1] 46 try: 47 # This code is semi-presumptuous - so it is put in a try finally to be safe. 48 final_record.begin = records[0].begin 49 final_record.begin_datetime = records[0].begin_datetime 50 final_record.start_type = records[0].start_type 51 for rec in records[0:-1]: 52 final_record.duration = (final_record.duration or 0) + (rec.duration or 0) 53 final_record.area = (final_record.area or 0) + (rec.area or 0) 54 final_record.avoid_count = (final_record.avoid_count or 0) + (rec.avoid_count or 0) 55 final_record.wash_count = (final_record.wash_count or 0) + (rec.wash_count or 0) 56 final_record.square_meter_area = (final_record.square_meter_area or 0) + ( 57 rec.square_meter_area or 0 58 ) 59 return final_record 60 except Exception: 61 # Return final record when an exception occurred 62 return final_record 63 # There are still a few unknown variables in this. 64 begin, end, duration, area = unpack_list(response, 4) 65 return CleanRecord(begin=begin, end=end, duration=duration, area=area) 66 raise ValueError(f"Unexpected clean record format: {response!r}")
Convert server responses to a CleanRecord.
def
convert( self, response: dict | list | int | str) -> roborock.data.v1.v1_containers.CleanRecord:
36 def convert(self, response: common.V1ResponseData) -> CleanRecord: 37 """Parse the response from the device into a CleanRecord.""" 38 if isinstance(response, list) and len(response) == 1: 39 response = response[0] 40 if isinstance(response, dict): 41 return CleanRecord.from_dict(response) 42 if isinstance(response, list): 43 if isinstance(response[-1], dict): 44 records = [CleanRecord.from_dict(rec) for rec in response] 45 final_record = records[-1] 46 try: 47 # This code is semi-presumptuous - so it is put in a try finally to be safe. 48 final_record.begin = records[0].begin 49 final_record.begin_datetime = records[0].begin_datetime 50 final_record.start_type = records[0].start_type 51 for rec in records[0:-1]: 52 final_record.duration = (final_record.duration or 0) + (rec.duration or 0) 53 final_record.area = (final_record.area or 0) + (rec.area or 0) 54 final_record.avoid_count = (final_record.avoid_count or 0) + (rec.avoid_count or 0) 55 final_record.wash_count = (final_record.wash_count or 0) + (rec.wash_count or 0) 56 final_record.square_meter_area = (final_record.square_meter_area or 0) + ( 57 rec.square_meter_area or 0 58 ) 59 return final_record 60 except Exception: 61 # Return final record when an exception occurred 62 return final_record 63 # There are still a few unknown variables in this. 64 begin, end, duration, area = unpack_list(response, 4) 65 return CleanRecord(begin=begin, end=end, duration=duration, area=area) 66 raise ValueError(f"Unexpected clean record format: {response!r}")
Parse the response from the device into a CleanRecord.
class
CleanSummaryTrait(roborock.data.v1.v1_containers.CleanSummaryWithDetail, roborock.devices.traits.v1.common.V1TraitMixin):
69class CleanSummaryTrait(CleanSummaryWithDetail, common.V1TraitMixin): 70 """Trait for managing the clean summary of Roborock devices.""" 71 72 command = RoborockCommand.GET_CLEAN_SUMMARY 73 converter = CleanSummaryConverter() 74 clean_record_converter = CleanRecordConverter() 75 76 async def refresh(self) -> None: 77 """Refresh the clean summary data and last clean record. 78 79 Assumes that the clean summary has already been fetched. 80 """ 81 await super().refresh() 82 if not self.records: 83 _LOGGER.debug("No clean records available in clean summary.") 84 self.last_clean_record = None 85 return 86 last_record_id = self.records[0] 87 self.last_clean_record = await self.get_clean_record(last_record_id) 88 89 async def get_clean_record(self, record_id: int) -> CleanRecord: 90 """Load a specific clean record by ID.""" 91 response = await self.rpc_channel.send_command(RoborockCommand.GET_CLEAN_RECORD, params=[record_id]) 92 try: 93 return self.clean_record_converter.convert(response) 94 except (TypeError, ValueError) as err: 95 raise RoborockParsingException( 96 trait_name=type(self).__name__, 97 command=RoborockCommand.GET_CLEAN_RECORD, 98 payload=response, 99 inner_error=err, 100 ) from err
Trait for managing the clean summary of Roborock devices.
command =
<RoborockCommand.GET_CLEAN_SUMMARY: 'get_clean_summary'>
The RoborockCommand used to fetch the trait data from the device (internal only).
converter =
CleanSummaryConverter
The converter used to parse the response from the device (internal only).
async def
refresh(self) -> None:
76 async def refresh(self) -> None: 77 """Refresh the clean summary data and last clean record. 78 79 Assumes that the clean summary has already been fetched. 80 """ 81 await super().refresh() 82 if not self.records: 83 _LOGGER.debug("No clean records available in clean summary.") 84 self.last_clean_record = None 85 return 86 last_record_id = self.records[0] 87 self.last_clean_record = await self.get_clean_record(last_record_id)
Refresh the clean summary data and last clean record.
Assumes that the clean summary has already been fetched.
89 async def get_clean_record(self, record_id: int) -> CleanRecord: 90 """Load a specific clean record by ID.""" 91 response = await self.rpc_channel.send_command(RoborockCommand.GET_CLEAN_RECORD, params=[record_id]) 92 try: 93 return self.clean_record_converter.convert(response) 94 except (TypeError, ValueError) as err: 95 raise RoborockParsingException( 96 trait_name=type(self).__name__, 97 command=RoborockCommand.GET_CLEAN_RECORD, 98 payload=response, 99 inner_error=err, 100 ) from err
Load a specific clean record by ID.