Skip to content

Commit

Permalink
🔧 fix for sensor_attributes (#1562)
Browse files Browse the repository at this point in the history
  • Loading branch information
al-one committed Mar 14, 2024
1 parent cebfe10 commit 69ee33b
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 57 deletions.
99 changes: 51 additions & 48 deletions custom_components/xiaomi_miot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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()
Expand All @@ -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}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 []
Expand All @@ -1618,38 +1617,40 @@ 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:
attrs = self._miio2miot.only_miio_props(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):
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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, {})

Expand All @@ -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:
Expand All @@ -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')
Expand All @@ -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:
Expand All @@ -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')
Expand All @@ -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 = []
Expand Down
7 changes: 1 addition & 6 deletions custom_components/xiaomi_miot/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 7 additions & 2 deletions custom_components/xiaomi_miot/core/xiaomi_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion custom_components/xiaomi_miot/vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit 69ee33b

Please sign in to comment.