diff --git a/custom_components/xiaomi_miot/__init__.py b/custom_components/xiaomi_miot/__init__.py index 66a3149207..0ec57abf94 100644 --- a/custom_components/xiaomi_miot/__init__.py +++ b/custom_components/xiaomi_miot/__init__.py @@ -2283,7 +2283,7 @@ def __init__(self, parent, attr, option=None, **kwargs): self._unique_id = f'{parent.unique_id}-{attr}' self._name = f'{parent.name} {attr}' self._state = STATE_UNKNOWN - self._attr_state = STATE_UNKNOWN + self._attr_state = None self._available = False self._parent = parent self._attr = attr diff --git a/custom_components/xiaomi_miot/core/xiaomi_cloud.py b/custom_components/xiaomi_miot/core/xiaomi_cloud.py index c0415ce3f8..c84b0a5ebe 100644 --- a/custom_components/xiaomi_miot/core/xiaomi_cloud.py +++ b/custom_components/xiaomi_miot/core/xiaomi_cloud.py @@ -249,7 +249,7 @@ def get_home_devices(self): } return rdt - async def async_get_devices(self, renew=False): + async def async_get_devices(self, renew=False, return_all=False): if not self.user_id: return None fnm = f'xiaomi_miot/devices-{self.user_id}-{self.default_server}.json' @@ -289,6 +289,8 @@ async def async_get_devices(self, renew=False): raise exc dvs = cds _LOGGER.warning('Get xiaomi devices filed: %s, use cached %s devices.', exc, len(cds)) + if return_all: + return dat return dvs async def async_renew_devices(self): @@ -325,6 +327,10 @@ async def async_get_devices_by_key(self, key, renew=False, filters=None): dat[k] = d return dat + async def async_get_homerooms(self, renew=False): + dat = await self.async_get_devices(renew=renew, return_all=True) or {} + return dat.get('homes') or [] + async def async_get_beaconkey(self, did): dat = {'did': did or self.miot_did, 'pdid': 1} rdt = await self.async_request_api('v2/device/blt_get_beaconkey', dat) or {} diff --git a/custom_components/xiaomi_miot/select.py b/custom_components/xiaomi_miot/select.py index 328ddfbbba..05c9060a54 100644 --- a/custom_components/xiaomi_miot/select.py +++ b/custom_components/xiaomi_miot/select.py @@ -169,7 +169,6 @@ def __init__(self, parent, attr, option=None): def update(self, data=None): super().update(data) self._attr_current_option = self._attr_state - self.async_write_ha_state() def select_option(self, option): """Change the selected option.""" diff --git a/custom_components/xiaomi_miot/vacuum.py b/custom_components/xiaomi_miot/vacuum.py index f3793c53b6..cacdf2f246 100644 --- a/custom_components/xiaomi_miot/vacuum.py +++ b/custom_components/xiaomi_miot/vacuum.py @@ -1,5 +1,6 @@ """Support for Xiaomi vacuums.""" import logging +import time from datetime import timedelta from functools import partial @@ -250,13 +251,22 @@ def __init__(self, config: dict, miot_service: MiotService): async def async_added_to_hass(self): await super().async_added_to_hass() - if self.miot_device: - try: - rooms = self.miot_device.send('get_room_mapping') - if rooms and rooms != 'unknown_method': - self._state_attrs['room_mapping'] = rooms - except (DeviceException, Exception): - pass + rooms = await self.get_room_mapping() + + if add_selects := self._add_entities.get('select'): + from .select import SelectSubEntity + sub = 'segments' + options = [ + r[2] + for r in rooms + if len(r) >= 3 + ] + self._subs[sub] = SelectSubEntity(self, sub, option={ + 'options': options, + 'select_option': self.start_clean_segment, + }) + add_selects([self._subs[sub]], update_before_add=False) + async def async_update(self): await super().async_update() @@ -273,6 +283,28 @@ async def async_update(self): if adt: await self.async_update_attrs(adt) + async def get_room_mapping(self): + if not self.miot_device: + return None + try: + rooms = self.miot_device.send('get_room_mapping') + if rooms and rooms != 'unknown_method': + homes = await self.xiaomi_cloud.async_get_homerooms() if self.xiaomi_cloud else [] + cloud_rooms = {} + for home in homes: + for room in home.get('roomlist', []): + cloud_rooms[room['id']] = room + for r in rooms: + room = cloud_rooms.get(r[1]) + if not room: + continue + r.append(room['name']) + self._state_attrs['room_mapping'] = rooms + return rooms + except (DeviceException, Exception): + pass + return None + @property def miio_props(self): return self._state_attrs.get('props') or {} @@ -314,6 +346,19 @@ def send_vacuum_command(self, command, params=None, **kwargs): raise NotImplementedError() return self.send_miio_command(command, params) + def start_clean_segment(self, segment, repeat=1, **kwargs): + segments = [] + for r in self._state_attrs.get('room_mapping', []): + if segment in r: + segments.append(r[0]) + break + if not segments: + self.return_to_base() + return False + self.pause() + time.sleep(0.5) + return self.send_miio_command('app_segment_clean', [{'segments': segments, 'repeat': repeat}]) + class MiotViomiVacuumEntity(MiotVacuumEntity): def __init__(self, config: dict, miot_service: MiotService):