diff --git a/custom_components/xiaomi_miot/__init__.py b/custom_components/xiaomi_miot/__init__.py index e16a48507..ea5c32fe3 100644 --- a/custom_components/xiaomi_miot/__init__.py +++ b/custom_components/xiaomi_miot/__init__.py @@ -1044,7 +1044,7 @@ async def async_update(self): self._state = attrs.get('power') == 'on' await self.async_update_attrs(attrs) - def _update_attr_sensor_entities(self, attrs, domain='sensor', option=None): + async def async_update_attr_sensor_entities(self, attrs, domain='sensor', option=None): add_sensors = self._add_entities.get(domain) opt = {**(option or {})} for a in attrs: @@ -1056,6 +1056,8 @@ def _update_attr_sensor_entities(self, attrs, domain='sensor', option=None): opt['dict_key'] = kys[1] if a not in self._state_attrs: continue + if not add_sensors: + continue tms = self._check_same_sub_entity(p, domain) if p in self._subs: self._subs[p].update_from_parent() @@ -1064,8 +1066,6 @@ def _update_attr_sensor_entities(self, attrs, domain='sensor', option=None): if tms <= 1: self.logger.info('%s: Device sub entity %s: %s already exists.', self.name_model, domain, p) continue - elif not add_sensors: - pass elif domain == 'sensor': from .sensor import BaseSensorSubEntity option = {'unique_id': f'{self._unique_did}-{p}', **opt} @@ -1101,35 +1101,34 @@ def turn_off(self, **kwargs): def update_attrs(self, attrs: dict, update_parent=False, update_subs=True): self._state_attrs.update(attrs or {}) - if self.hass and self.platform and update_subs: - tps = cv.ensure_list(self.custom_config('attributes_template')) - for tpl in tps: - if not tpl: - continue - tpl = CUSTOM_TEMPLATES.get(tpl, tpl) - tpl = cv.template(tpl) - tpl.hass = self.hass - adt = tpl.render({'data': self._state_attrs}) or {} - if isinstance(adt, dict): - if adt.pop('_override', False): - self._state_attrs = adt - else: - self._state_attrs.update(adt) if update_parent and hasattr(self, '_parent'): if self._parent and hasattr(self._parent, 'update_attrs'): getattr(self._parent, 'update_attrs')(attrs or {}, update_parent=False) + return self._state_attrs + + async def async_update_attrs(self, attrs: dict, update_parent=False, update_subs=True): + self._state_attrs.update(attrs or {}) if update_subs: + if self.hass and self.platform: + tps = cv.ensure_list(self.custom_config('attributes_template')) + for tpl in tps: + if not tpl: + continue + tpl = CUSTOM_TEMPLATES.get(tpl, tpl) + tpl = cv.template(tpl) + tpl.hass = self.hass + adt = tpl.async_render({'data': self._state_attrs}) or {} + if isinstance(adt, dict): + if adt.pop('_override', False): + self._state_attrs = adt + else: + self._state_attrs.update(adt) if pls := self.custom_config_list('sensor_attributes'): - self._update_attr_sensor_entities(pls, domain='sensor') + await self.async_update_attr_sensor_entities(pls, domain='sensor') if pls := self.custom_config_list('binary_sensor_attributes'): - self._update_attr_sensor_entities(pls, domain='binary_sensor') + await self.async_update_attr_sensor_entities(pls, domain='binary_sensor') return self._state_attrs - async def async_update_attrs(self, *args, **kwargs): - return await self.hass.async_add_executor_job( - partial(self.update_attrs, *args, **kwargs) - ) - class MiotEntityInterface: _miot_service = None @@ -1600,10 +1599,10 @@ async def async_update_for_main_entity(self): # update miio prop/event in cloud if cls := self.custom_config_list('miio_cloud_records'): - await self.hass.async_add_executor_job(partial(self.update_miio_cloud_records, cls)) + await self.async_update_miio_cloud_records(pls) if pls := self.custom_config_list('miio_cloud_props'): - await self.hass.async_add_executor_job(partial(self.update_miio_cloud_props, pls)) + await self.async_update_miio_cloud_props(pls) # update micloud statistics in cloud cls = self.custom_config_list('micloud_statistics') or [] @@ -1618,17 +1617,17 @@ async def async_update_for_main_entity(self): } cls = [*cls, dic] if cls: - await self.hass.async_add_executor_job(partial(self.update_micloud_statistics, cls)) + await self.async_update_micloud_statistics(cls) # update miio properties in lan if pls := self._vars.get('miio_properties', []): - await self.hass.async_add_executor_job(partial(self.update_miio_props, pls)) + await self.async_update_miio_props(pls) # update miio commands in lan if cls := self.custom_config_json('miio_commands'): - await self.hass.async_add_executor_job(partial(self.update_miio_commands, cls)) + await self.async_update_miio_commands(cls) - def update_miio_props(self, props): + async def async_update_miio_props(self, props): if not self.miot_device: return if self._miio2miot: @@ -1636,20 +1635,22 @@ def update_miio_props(self, props): else: try: num = self.custom_config_integer('chunk_properties') or 15 - attrs = self._device.get_properties(props, max_properties=num) + attrs = await self.hass.async_add_executor_job( + partial(self._device.get_properties, props, max_properties=num) + ) except DeviceException as exc: self.logger.warning('%s: Got miio properties %s failed: %s', self.name_model, props, exc) return if len(props) != len(attrs): - self.update_attrs({ + await self.async_update_attrs({ 'miio.props': attrs, }) return attrs = dict(zip(map(lambda x: f'miio.{x}', props), attrs)) self.logger.debug('%s: Got miio properties: %s', self.name_model, attrs) - self.update_attrs(attrs) + await self.async_update_attrs(attrs) - def update_miio_commands(self, commands): + async def async_update_miio_commands(self, commands): if not self.miot_device: return if isinstance(commands, dict): @@ -1663,7 +1664,9 @@ def update_miio_commands(self, commands): cmd = cfg.get('method') pms = cfg.get('params') or [] try: - attrs = self._device.send(cmd, pms) + attrs = await self.hass.async_add_executor_job( + partial(self._device.send, cmd, pms) + ) except DeviceException as exc: self.logger.warning('%s: Send miio command %s(%s) failed: %s', self.name_model, cmd, cfg, exc) continue @@ -1675,9 +1678,9 @@ def update_miio_commands(self, commands): else: attrs = dict(zip(props, attrs)) self.logger.debug('%s: Got miio properties: %s', self.name_model, attrs) - self.update_attrs(attrs) + await self.async_update_attrs(attrs) - def update_miio_cloud_props(self, keys): + async def async_update_miio_cloud_props(self, keys): did = str(self.miot_did) mic = self.xiaomi_cloud if not did or not mic: @@ -1691,7 +1694,7 @@ def update_miio_cloud_props(self, keys): 'did': did, 'props': kls, } - rdt = mic.request_miot_api('device/batchdevicedatas', [pms]) or {} + rdt = await mic.async_request_api('device/batchdevicedatas', [pms]) or {} self.logger.debug('%s: Got miio cloud props: %s', self.name_model, rdt) props = (rdt.get('result') or {}).get(did, {}) @@ -1700,12 +1703,12 @@ def update_miio_cloud_props(self, keys): tpl = CUSTOM_TEMPLATES.get(tpl, tpl) tpl = cv.template(tpl) tpl.hass = self.hass - attrs = tpl.render({'props': props}) + attrs = tpl.async_render({'props': props}) else: attrs = props - self.update_attrs(attrs) + await self.async_update_attrs(attrs) - def update_miio_cloud_records(self, keys): + async def async_update_miio_cloud_records(self, keys): did = self.miot_did mic = self.xiaomi_cloud if not did or not mic: @@ -1723,13 +1726,13 @@ def update_miio_cloud_records(self, keys): } if gby: kws['group'] = gby - rdt = mic.get_user_device_data(did, key, typ, **kws) or [] + rdt = await mic.async_get_user_device_data(did, key, typ, **kws) or [] tpl = self.custom_config(f'miio_{typ}_{key}_template') if tpl: tpl = CUSTOM_TEMPLATES.get(tpl, tpl) tpl = cv.template(tpl) tpl.hass = self.hass - rls = tpl.render({'result': rdt}) + rls = tpl.async_render({'result': rdt}) else: rls = [ v.get('value') @@ -1741,9 +1744,9 @@ def update_miio_cloud_records(self, keys): else: attrs[f'{typ}.{key}'] = rls if attrs: - self.update_attrs(attrs) + await self.async_update_attrs(attrs) - def update_micloud_statistics(self, lst): + async def async_update_micloud_statistics(self, lst): did = self.miot_did mic = self.xiaomi_cloud if not did or not mic: @@ -1762,14 +1765,14 @@ def update_micloud_statistics(self, lst): 'time_end': now + 60, 'limit': int(c.get('limit') or 1), } - rdt = mic.request_miot_api('v2/user/statistics', pms) or {} + rdt = await mic.async_request_api('v2/user/statistics', pms) or {} self.logger.debug('%s: Got micloud statistics: %s', self.name_model, rdt) tpl = c.get('template') if tpl: tpl = CUSTOM_TEMPLATES.get(tpl, tpl) tpl = cv.template(tpl) tpl.hass = self.hass - rls = tpl.render(rdt) + rls = tpl.async_render(rdt) else: rls = [ v.get('value') @@ -1781,7 +1784,7 @@ def update_micloud_statistics(self, lst): elif isinstance(rls, dict): attrs.update(rls) if attrs: - self.update_attrs(attrs) + await self.async_update_attrs(attrs) def get_properties(self, mapping, update_entity=False, throw=False, **kwargs): results = [] diff --git a/custom_components/xiaomi_miot/binary_sensor.py b/custom_components/xiaomi_miot/binary_sensor.py index 145773b87..86c67a002 100644 --- a/custom_components/xiaomi_miot/binary_sensor.py +++ b/custom_components/xiaomi_miot/binary_sensor.py @@ -343,12 +343,7 @@ async def async_update(self): if isinstance(mic, MiotCloud): now = int(time.time()) ofs = self.custom_config_integer('time_start_offset') or -86400 * 3 - dlg = await self.hass.async_add_executor_job(partial( - mic.get_last_device_data, - self.miot_did, - 'device_log', - time_start=now + ofs, - )) + dlg = await mic.async_get_last_device_data(self.miot_did, 'device_log', time_start=now + ofs) pes = json.loads(dlg or '[]') adt = {} typ = None diff --git a/custom_components/xiaomi_miot/core/xiaomi_cloud.py b/custom_components/xiaomi_miot/core/xiaomi_cloud.py index 06b2b19f3..8156be994 100644 --- a/custom_components/xiaomi_miot/core/xiaomi_cloud.py +++ b/custom_components/xiaomi_miot/core/xiaomi_cloud.py @@ -100,6 +100,11 @@ def request_miot_spec(self, api, params=None): raise MiCloudException(json.dumps(rdt)) return rls + async def async_get_user_device_data(self, *args, **kwargs): + return await self.hass.async_add_executor_job( + partial(self.get_user_device_data, *args, **kwargs) + ) + def get_user_device_data(self, did, key, typ='prop', raw=False, **kwargs): now = int(time.time()) timeout = kwargs.pop('timeout', self.http_timeout) @@ -115,10 +120,10 @@ def get_user_device_data(self, did, key, typ='prop', raw=False, **kwargs): rdt = self.request_miot_api('user/get_user_device_data', params, timeout=timeout) or {} return rdt if raw else rdt.get('result') - def get_last_device_data(self, did, key, typ='prop', **kwargs): + async def async_get_last_device_data(self, did, key, typ='prop', **kwargs): kwargs['raw'] = False kwargs['limit'] = 1 - rls = self.get_user_device_data(did, key, typ, **kwargs) or [None] + rls = await self.async_get_user_device_data(did, key, typ, **kwargs) or [None] rdt = rls.pop(0) or {} if kwargs.get('not_value'): return rdt diff --git a/custom_components/xiaomi_miot/vacuum.py b/custom_components/xiaomi_miot/vacuum.py index 06ef1392a..3f3a81699 100644 --- a/custom_components/xiaomi_miot/vacuum.py +++ b/custom_components/xiaomi_miot/vacuum.py @@ -387,7 +387,7 @@ async def async_update(self): if not self._available: return if self._miio2miot: - await self.hass.async_add_executor_job(partial(self.update_miio_props, self._miio_props)) + await self.async_update_miio_props(self._miio_props) props = self._state_attrs or {} adt = {} if 'miio.s_area' in props: