Skip to content

Commit

Permalink
add info entity
Browse files Browse the repository at this point in the history
  • Loading branch information
al-one committed Sep 25, 2024
1 parent 820e439 commit 605316a
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 26 deletions.
16 changes: 15 additions & 1 deletion custom_components/xiaomi_miot/core/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class BaseConv:
option: dict = None

def __post_init__(self):
self.option = {}
if self.option is None:
self.option = {}

# to hass
def decode(self, device: 'Device', payload: dict, value):
Expand All @@ -32,6 +33,19 @@ def encode(self, device: 'Device', payload: dict, value):
params.update({'did': device.did, 'value': value})
payload.setdefault('params', []).append(params)

@dataclass
class InfoConv(BaseConv):
attr: str = 'info'
domain: str = 'sensor'

def decode(self, device: 'Device', payload: dict, value):
payload.update({
self.attr: value,
'updater': device.data.get('updater'),
})
if device.miot_results:
payload.update(device.miot_results.to_attributes())

@dataclass
class MiotPropConv(BaseConv):
prop: 'MiotProperty' = None
Expand Down
47 changes: 42 additions & 5 deletions custom_components/xiaomi_miot/core/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

from .const import DOMAIN, DEVICE_CUSTOMIZES, MIOT_LOCAL_MODELS, DEFAULT_NAME, CONF_CONN_MODE, DEFAULT_CONN_MODE
from .hass_entry import HassEntry
from .converters import BaseConv, MiotPropConv, MiotPropValueConv, MiotActionConv
from .hass_entity import XEntity, convert_unique_id
from .converters import BaseConv, InfoConv, MiotPropConv, MiotPropValueConv, MiotActionConv
from .miot_spec import MiotSpec, MiotResults
from .miio2miot import Miio2MiotHelper
from .xiaomi_cloud import MiotCloud, MiCloudException
Expand All @@ -29,6 +30,7 @@
from . import BasicEntity

_LOGGER = logging.getLogger(__name__)
InfoConverter = InfoConv(option={'icon': 'mdi:information'})


class DeviceInfo:
Expand Down Expand Up @@ -169,7 +171,13 @@ def sw_version(self):
if self.info.hardware_version:
swv = f'{swv}@{self.info.hardware_version}'
updater = self.data.get('updater')
if updater and updater not in ['none']:
emoji = {
'local': '🛜',
'cloud': '☁️',
}.get(updater)
if emoji:
swv = f'{swv} {emoji}'
elif updater and updater not in ['none']:
swv = f'{swv} ({updater})'
return swv

Expand Down Expand Up @@ -271,6 +279,9 @@ def init_converters(self):
if not self.spec:
return

self.converters.append(InfoConverter)
self.dispatch_info()

for d in [
'sensor', 'binary_sensor', 'switch', 'number', 'select', 'button',
# 'fan', 'cover', 'scanner', 'number_select',
Expand Down Expand Up @@ -304,6 +315,24 @@ def init_converters(self):
for action in srv.get_actions(*als):
self.converters.append(MiotActionConv(action.full_name, d, action=action))

def add_entities(self, domain):
for conv in self.converters:
if conv.domain != domain:
continue
key = convert_unique_id(conv)
entity = self.entities.get(key)
if entity:
continue
cls = XEntity.CLS.get(domain)
adder = self.entry.adders.get(domain)
if not (cls and adder):
continue
entity = cls(self, conv)
self.add_entity(entity)
adder([entity], update_before_add=False)
_LOGGER.info('New entity: %s', entity)
self.dispatch_info()

def add_entity(self, entity: 'BasicEntity'):
if entity not in self.entities:
self.entities[entity.unique_id] = entity
Expand All @@ -316,11 +345,17 @@ def remove_listener(self, handler: Callable):
if handler in self.listeners:
self.listeners.remove(handler)

def dispatch(self, data: dict):
_LOGGER.info('%s: Device updated: %s', self.name_model, data)
def dispatch(self, data: dict, log=True):
if log:
_LOGGER.info('%s: Device updated: %s', self.name_model, data)
for handler in self.listeners:
handler(data)

def dispatch_info(self):
info = {}
InfoConverter.decode(self, info, self.info.host)
self.dispatch(info, log=False)

def decode(self, data: dict | list) -> dict:
"""Decode data from device."""
payload = {}
Expand Down Expand Up @@ -497,13 +532,15 @@ async def update_miot_status(
)

if self.miot_results.updater != self.data.get('updater'):
self.data['updater'] = self.miot_results.updater
dev_reg = dr.async_get(self.hass)
if dev := dev_reg.async_get_device(self.identifiers):
self.data['updater'] = self.miot_results.updater
dev_reg.async_update_device(dev.id, sw_version=self.sw_version)
_LOGGER.info('%s: State updater: %s', self.name_model, self.sw_version)
if results:
self.data['miot_results'] = results
self.dispatch(self.decode(results))
self.dispatch_info()
return self.miot_results


Expand Down
21 changes: 15 additions & 6 deletions custom_components/xiaomi_miot/core/hass_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
from typing import TYPE_CHECKING, Optional, Callable
from functools import cached_property

from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity import Entity, EntityCategory
from homeassistant.helpers.restore_state import ExtraStoredData, RestoredExtraData
import homeassistant.helpers.config_validation as cv

from .utils import get_customize_via_entity, wildcard_models
from .miot_spec import MiotService, MiotProperty, MiotAction
from .converters import BaseConv, MiotPropConv, MiotActionConv
from .converters import BaseConv, InfoConv, MiotPropConv, MiotActionConv

if TYPE_CHECKING:
from .device import Device
Expand All @@ -20,6 +20,7 @@

class BasicEntity(Entity):
device: 'Device' = None
conv: 'BaseConv' = None

def custom_config(self, key=None, default=None):
return get_customize_via_entity(self, key, default)
Expand Down Expand Up @@ -105,9 +106,8 @@ def __init__(self, device: 'Device', conv: 'BaseConv'):
self._attr_available = True

else:
prefix = device.spec.generate_entity_id(self, self.attr)
self.entity_id = f'{prefix}_{self.attr}'
self._attr_name = self.attr.replace('_', '').title()
self.entity_id = device.spec.generate_entity_id(self, self.attr, conv.domain)
# self._attr_name = self.attr.replace('_', '').title()
self._attr_translation_key = self.attr

self.listen_attrs: set = {self.attr}
Expand All @@ -117,7 +117,14 @@ def __init__(self, device: 'Device', conv: 'BaseConv'):
'converter': f'{conv}'.replace('custom_components.xiaomi_miot.core.miot_spec.', ''), # TODO
}

self._attr_icon = conv.option.get('icon')

if isinstance(conv, InfoConv):
self._attr_available = True
self._attr_entity_category = EntityCategory.DIAGNOSTIC

self.on_init()
self.device.add_listener(self.on_device_update)

@property
def unique_mac(self):
Expand All @@ -130,6 +137,9 @@ def on_device_update(self, data: dict):
state_change = False
self._attr_available = True

if isinstance(self.conv, InfoConv):
self._attr_extra_state_attributes.update(data)

if keys := self.listen_attrs & data.keys():
self.set_state(data)
state_change = True
Expand Down Expand Up @@ -158,7 +168,6 @@ def extra_restore_state_data(self) -> ExtraStoredData | None:

async def async_added_to_hass(self) -> None:
self.added = True
self.device.add_listener(self.on_device_update)

if call := getattr(self, 'async_get_last_extra_data', None):
data: RestoredExtraData = await call()
Expand Down
15 changes: 1 addition & 14 deletions custom_components/xiaomi_miot/core/hass_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .miio2miot import Miio2MiotHelper
from .xiaomi_cloud import MiotCloud
from .hass_entity import XEntity, convert_unique_id

if TYPE_CHECKING:
from .device import Device
Expand Down Expand Up @@ -59,19 +58,7 @@ def new_adder(self, domain, adder: AddEntitiesCallback):
_LOGGER.info('New adder: %s', [domain, adder])

for device in self.devices.values():
for conv in device.converters:
if conv.domain != domain:
continue
key = convert_unique_id(conv)
entity = device.entities.get(key)
if not entity:
cls = XEntity.CLS.get(domain)
if not cls:
continue
entity = cls(device, conv)
device.add_entity(entity)
adder([entity], update_before_add=False)
_LOGGER.info('New entity: %s', entity)
device.add_entities(domain)

return self

Expand Down
3 changes: 3 additions & 0 deletions custom_components/xiaomi_miot/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@
},
"entity": {
"sensor": {
"info": {
"name": "Info"
},
"lock": {
"state": {
"bluetooth": "Bluetooth",
Expand Down
3 changes: 3 additions & 0 deletions custom_components/xiaomi_miot/translations/zh-Hans.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@
},
"entity": {
"sensor": {
"info": {
"name": "信息"
},
"lock": {
"state": {
"bluetooth": "蓝牙",
Expand Down

0 comments on commit 605316a

Please sign in to comment.