diff --git a/custom_components/xiaomi_home/cover.py b/custom_components/xiaomi_home/cover.py index f2ebaeb..6dbdaf4 100644 --- a/custom_components/xiaomi_home/cover.py +++ b/custom_components/xiaomi_home/cover.py @@ -60,16 +60,16 @@ from homeassistant.components.cover import ( ) from .miot.miot_spec import MIoTSpecProperty -from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity +from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity from .miot.const import DOMAIN _LOGGER = logging.getLogger(__name__) async def async_setup_entry( - hass: HomeAssistant, - config_entry: ConfigEntry, - async_add_entities: AddEntitiesCallback, + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback ) -> None: """Set up a config entry.""" device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][ @@ -82,6 +82,10 @@ async def async_setup_entry( data.spec.device_class = CoverDeviceClass.CURTAIN elif data.spec.name == 'window-opener': data.spec.device_class = CoverDeviceClass.WINDOW + elif data.spec.name == 'motor-controller': + data.spec.device_class = CoverDeviceClass.SHUTTER + elif data.spec.name == 'airer': + data.spec.device_class = CoverDeviceClass.BLIND new_entities.append( Cover(miot_device=miot_device, entity_data=data)) @@ -100,6 +104,7 @@ class Cover(MIoTServiceEntity, CoverEntity): _prop_status_opening: Optional[int] _prop_status_closing: Optional[int] _prop_status_stop: Optional[int] + _prop_status_closed: Optional[int] _prop_current_position: Optional[MIoTSpecProperty] _prop_target_position: Optional[MIoTSpecProperty] _prop_position_value_min: Optional[int] @@ -123,6 +128,7 @@ class Cover(MIoTServiceEntity, CoverEntity): self._prop_status_opening = None self._prop_status_closing = None self._prop_status_stop = None + self._prop_status_closed = None self._prop_current_position = None self._prop_target_position = None self._prop_position_value_min = None @@ -137,15 +143,15 @@ class Cover(MIoTServiceEntity, CoverEntity): 'motor-control value_list is None, %s', self.entity_id) continue for item in prop.value_list.items: - if item.name in {'open'}: + if item.name in {'open', 'up'}: self._attr_supported_features |= ( CoverEntityFeature.OPEN) self._prop_motor_value_open = item.value - elif item.name in {'close'}: + elif item.name in {'close', 'down'}: self._attr_supported_features |= ( CoverEntityFeature.CLOSE) self._prop_motor_value_close = item.value - elif item.name in {'pause'}: + elif item.name in {'pause', 'stop'}: self._attr_supported_features |= ( CoverEntityFeature.STOP) self._prop_motor_value_pause = item.value @@ -156,12 +162,14 @@ class Cover(MIoTServiceEntity, CoverEntity): 'status value_list is None, %s', self.entity_id) continue for item in prop.value_list.items: - if item.name in {'opening', 'open'}: + if item.name in {'opening', 'open', 'up'}: self._prop_status_opening = item.value - elif item.name in {'closing', 'close'}: + elif item.name in {'closing', 'close', 'down'}: self._prop_status_closing = item.value elif item.name in {'stop', 'pause'}: self._prop_status_stop = item.value + elif item.name in {'closed'}: + self._prop_status_closed = item.value self._prop_status = prop elif prop.name == 'current-position': self._prop_current_position = prop @@ -209,28 +217,56 @@ class Cover(MIoTServiceEntity, CoverEntity): 0: the cover is closed, 100: the cover is fully opened, None: unknown. """ + if self._prop_current_position is None: + # Assume that the current position is the same as the target + # position when the current position is not defined in the device's + # MIoT-Spec-V2. + return None if (self._prop_target_position + is None) else self.get_prop_value( + prop=self._prop_target_position) pos = self.get_prop_value(prop=self._prop_current_position) - if pos is None: + if pos is None or self._prop_position_value_range is None: return None return round(pos*100/self._prop_position_value_range) @property def is_opening(self) -> Optional[bool]: """Return if the cover is opening.""" - if self._prop_status is None: - return None - return self.get_prop_value( - prop=self._prop_status) == self._prop_status_opening + if self._prop_status and self._prop_status_opening is not None: + return self.get_prop_value( + prop=self._prop_status) == self._prop_status_opening + # The status is prior to the numerical relationship of the current + # position and the target position when determining whether the cover + # is opening. + if (self._prop_target_position and + self.current_cover_position is not None): + return (self.current_cover_position + < self.get_prop_value(prop=self._prop_target_position)) + return None @property def is_closing(self) -> Optional[bool]: """Return if the cover is closing.""" - if self._prop_status is None: - return None - return self.get_prop_value( - prop=self._prop_status) == self._prop_status_closing + if self._prop_status and self._prop_status_closing is not None: + return self.get_prop_value( + prop=self._prop_status) == self._prop_status_closing + # The status is prior to the numerical relationship of the current + # position and the target position when determining whether the cover + # is closing. + if (self._prop_target_position and + self.current_cover_position is not None): + return (self.current_cover_position + > self.get_prop_value(prop=self._prop_target_position)) + return None @property def is_closed(self) -> Optional[bool]: """Return if the cover is closed.""" - return self.get_prop_value(prop=self._prop_current_position) == 0 + if self.current_cover_position is not None: + return self.current_cover_position == 0 + # The current position is prior to the status when determining + # whether the cover is closed. + if self._prop_status and self._prop_status_closed is not None: + return (self.get_prop_value( + prop=self._prop_status) == self._prop_status_closed) + return None diff --git a/custom_components/xiaomi_home/miot/specs/specv2entity.py b/custom_components/xiaomi_home/miot/specs/specv2entity.py index 0061f79..444ae0e 100644 --- a/custom_components/xiaomi_home/miot/specs/specv2entity.py +++ b/custom_components/xiaomi_home/miot/specs/specv2entity.py @@ -324,7 +324,9 @@ SPEC_SERVICE_TRANS_MAP: dict = { }, 'entity': 'cover' }, - 'window-opener': 'curtain' + 'window-opener': 'curtain', + 'motor-controller': 'curtain', + 'airer': 'curtain' } """SPEC_PROP_TRANS_MAP