diff --git a/custom_components/xiaomi_home/media_player.py b/custom_components/xiaomi_home/media_player.py index f863d92..ecc17ed 100644 --- a/custom_components/xiaomi_home/media_player.py +++ b/custom_components/xiaomi_home/media_player.py @@ -430,15 +430,16 @@ class FeatureState(MIoTServiceEntity, MediaPlayerEntity): elif item.name in {'pause', 'paused'}: self._playing_state_map[ item.value] = MediaPlayerState.PAUSED - self._prop_playing_state = prop + self._prop_playing_state = prop @property def state(self) -> Optional[MediaPlayerState]: """The current state.""" - return (self.get_map_value(map_=self._playing_state_map, - key=self.get_prop_value( - prop=self._prop_playing_state)) - if self._prop_playing_state else MediaPlayerState.ON) + current_state = self.get_prop_value( + prop=self._prop_playing_state) if self._prop_playing_state else None + return (MediaPlayerState.ON if + (current_state is None) else self.get_map_value( + map_=self._playing_state_map, key=current_state)) class WifiSpeaker(FeatureVolumeSet, FeatureVolumeMute, FeaturePlay, diff --git a/custom_components/xiaomi_home/miot/miot_client.py b/custom_components/xiaomi_home/miot/miot_client.py index 31e80af..61cfdf9 100644 --- a/custom_components/xiaomi_home/miot/miot_client.py +++ b/custom_components/xiaomi_home/miot/miot_client.py @@ -79,6 +79,12 @@ from .miot_i18n import MIoTI18n _LOGGER = logging.getLogger(__name__) +REFRESH_PROPS_DELAY = 0.2 +REFRESH_PROPS_RETRY_DELAY = 3 +REFRESH_CLOUD_DEVICES_DELAY = 6 +REFRESH_CLOUD_DEVICES_RETRY_DELAY = 60 +REFRESH_GATEWAY_DEVICES_DELAY = 3 + @dataclass class MIoTClientSub: """MIoT client subscription.""" @@ -717,7 +723,7 @@ class MIoTClient: if self._refresh_props_timer: return self._refresh_props_timer = self._main_loop.call_later( - 0.2, lambda: self._main_loop.create_task( + REFRESH_PROPS_DELAY, lambda: self._main_loop.create_task( self.__refresh_props_handler())) async def get_prop_async(self, did: str, siid: int, piid: int) -> Any: @@ -1433,9 +1439,19 @@ class MIoTClient: async def __refresh_cloud_devices_async(self) -> None: _LOGGER.debug( 'refresh cloud devices, %s, %s', self._uid, self._cloud_server) - self._refresh_cloud_devices_timer = None - result = await self._http.get_devices_async( - home_ids=list(self._entry_data.get('home_selected', {}).keys())) + if self._refresh_cloud_devices_timer: + self._refresh_cloud_devices_timer.cancel() + self._refresh_cloud_devices_timer = None + try: + result = await self._http.get_devices_async( + home_ids=list(self._entry_data.get('home_selected', {}).keys())) + except Exception as err: # pylint: disable=broad-exception-caught + _LOGGER.error('refresh cloud devices failed, %s', err) + self._refresh_cloud_devices_timer = self._main_loop.call_later( + REFRESH_CLOUD_DEVICES_RETRY_DELAY, + lambda: self._main_loop.create_task( + self.__refresh_cloud_devices_async())) + return if not result and 'devices' not in result: self.__show_client_error_notify( message=self._i18n.translate( @@ -1481,17 +1497,11 @@ class MIoTClient: _LOGGER.debug( 'request refresh cloud devices, %s, %s', self._uid, self._cloud_server) - if immediately: - if self._refresh_cloud_devices_timer: - self._refresh_cloud_devices_timer.cancel() - self._refresh_cloud_devices_timer = self._main_loop.call_later( - 0, lambda: self._main_loop.create_task( - self.__refresh_cloud_devices_async())) - return + delay_sec : int = 0 if immediately else REFRESH_CLOUD_DEVICES_DELAY if self._refresh_cloud_devices_timer: - return + self._refresh_cloud_devices_timer.cancel() self._refresh_cloud_devices_timer = self._main_loop.call_later( - 6, lambda: self._main_loop.create_task( + delay_sec, lambda: self._main_loop.create_task( self.__refresh_cloud_devices_async())) @final @@ -1615,7 +1625,8 @@ class MIoTClient: return self._mips_local_state_changed_timers[group_id] = ( self._main_loop.call_later( - 3, lambda: self._main_loop.create_task( + REFRESH_GATEWAY_DEVICES_DELAY, + lambda: self._main_loop.create_task( self.__refresh_gw_devices_with_group_id_async( group_id=group_id)))) @@ -1769,7 +1780,7 @@ class MIoTClient: self._refresh_props_retry_count = 0 if self._refresh_props_list: self._refresh_props_timer = self._main_loop.call_later( - 0.2, lambda: self._main_loop.create_task( + REFRESH_PROPS_DELAY, lambda: self._main_loop.create_task( self.__refresh_props_handler())) else: self._refresh_props_timer = None @@ -1788,7 +1799,7 @@ class MIoTClient: _LOGGER.info( 'refresh props failed, retry, %s', self._refresh_props_retry_count) self._refresh_props_timer = self._main_loop.call_later( - 3, lambda: self._main_loop.create_task( + REFRESH_PROPS_RETRY_DELAY, lambda: self._main_loop.create_task( self.__refresh_props_handler())) @final diff --git a/custom_components/xiaomi_home/miot/miot_mips.py b/custom_components/xiaomi_home/miot/miot_mips.py index bdc96b6..3d66db4 100644 --- a/custom_components/xiaomi_home/miot/miot_mips.py +++ b/custom_components/xiaomi_home/miot/miot_mips.py @@ -519,15 +519,12 @@ class _MipsClient(ABC): if not self._mqtt or not self._mqtt.is_connected(): self.log_error(f'mips sub when not connected, {topic}') return - try: - if topic not in self._mips_sub_pending_map: - self._mips_sub_pending_map[topic] = 0 - if not self._mips_sub_pending_timer: - self._mips_sub_pending_timer = self._internal_loop.call_later( - 0.01, self.__mips_sub_internal_pending_handler, topic) - except Exception as err: # pylint: disable=broad-exception-caught - # Catch all exception - self.log_error(f'mips sub internal error, {topic}. {err}') + + if topic not in self._mips_sub_pending_map: + self._mips_sub_pending_map[topic] = 0 + if not self._mips_sub_pending_timer: + self._mips_sub_pending_timer = self._internal_loop.call_later( + 0.01, self.__mips_sub_internal_pending_handler, topic) @final def _mips_unsub_internal(self, topic: str) -> None: @@ -736,11 +733,16 @@ class _MipsClient(ABC): self.log_error(f'retry mips sub internal error, {topic}') continue subbed_count += 1 - result, mid = self._mqtt.subscribe(topic, qos=self.MIPS_QOS) - if result == MQTT_ERR_SUCCESS: - self._mips_sub_pending_map.pop(topic) - self.log_debug(f'mips sub internal success, {topic}') - continue + result = mid = None + try: + result, mid = self._mqtt.subscribe(topic, qos=self.MIPS_QOS) + if result == MQTT_ERR_SUCCESS: + self._mips_sub_pending_map.pop(topic) + self.log_debug(f'mips sub internal success, {topic}') + continue + except Exception as err: # pylint: disable=broad-exception-caught + # Catch all exception + self.log_error(f'mips sub internal error, {topic}. {err}') self._mips_sub_pending_map[topic] = count+1 self.log_error( f'retry mips sub internal, {count}, {topic}, {result}, {mid}') diff --git a/custom_components/xiaomi_home/miot/miot_network.py b/custom_components/xiaomi_home/miot/miot_network.py index 58751cc..911fb9c 100644 --- a/custom_components/xiaomi_home/miot/miot_network.py +++ b/custom_components/xiaomi_home/miot/miot_network.py @@ -291,7 +291,7 @@ class MIoTNetwork: return self._main_loop.time() - start_ts return self._DETECT_TIMEOUT except Exception as err: # pylint: disable=broad-exception-caught - print(err) + _LOGGER.debug('ping error, %s',err) return self._DETECT_TIMEOUT async def __http_async(self, url: str) -> float: diff --git a/custom_components/xiaomi_home/miot/specs/specv2entity.py b/custom_components/xiaomi_home/miot/specs/specv2entity.py index ff7849d..c824ecd 100644 --- a/custom_components/xiaomi_home/miot/specs/specv2entity.py +++ b/custom_components/xiaomi_home/miot/specs/specv2entity.py @@ -325,10 +325,12 @@ SPEC_DEVICE_TRANS_MAP: dict = { }, 'play-control': { 'required': { + 'properties': { + 'playing-state': {'read'} + }, 'actions': {'play'} }, 'optional': { - 'properties': {'playing-state'}, 'actions': {'pause', 'stop', 'next', 'previous'} } }