Skip to content

Commit

Permalink
apply converter for sensor
Browse files Browse the repository at this point in the history
  • Loading branch information
al-one committed Sep 18, 2024
1 parent 24f029d commit da15f08
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 30 deletions.
19 changes: 1 addition & 18 deletions custom_components/xiaomi_miot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,7 @@ def __init__(self, name, device, **kwargs):
'home_room': self.device.info.home_room,
'entity_class': self.__class__.__name__,
}
self._attr_device_info = self.device.hass_device_info
self._supported_features = 0
self._props = ['power']
self._success_result = ['ok']
Expand Down Expand Up @@ -917,24 +918,6 @@ def extra_state_attributes(self):
def supported_features(self):
return self._supported_features

@property
def device_info(self):
swv = self._miio_info.firmware_version
if self._miio_info.hardware_version:
swv = f'{swv}@{self._miio_info.hardware_version}'
updater = self._state_attrs.get('state_updater')
if updater and updater not in ['none']:
swv = f'{swv} ({updater})'
return {
'identifiers': {(DOMAIN, self._unique_did)},
'name': self.device_name,
'model': self.model,
'manufacturer': (self.model or 'Xiaomi').split('.', 1)[0],
'sw_version': swv,
'suggested_area': self.device.info.room_name,
'configuration_url': f'https://home.miot-spec.com/s/{self.model}',
}

async def async_added_to_hass(self):
await super().async_added_to_hass()
if self.platform:
Expand Down
31 changes: 25 additions & 6 deletions custom_components/xiaomi_miot/core/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from miio.miot_device import MiotDevice as MiotDeviceBase

if TYPE_CHECKING:
from .. import BaseEntity
from . import XEntity

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -117,10 +117,11 @@ class Device:
_local_state = None

def __init__(self, info: DeviceInfo, entry: HassEntry):
self.data = {}
self.info = info
self.hass = entry.hass
self.entry = entry
self.entities: list['BaseEntity'] = []
self.entities: dict[str, 'XEntity'] = {}
self.listeners: list[Callable] = []
self.converters: list[BaseConv] = []

Expand Down Expand Up @@ -154,6 +155,24 @@ def local_only(self):
def cloud_only(self):
return self.conn_mode == 'cloud'

@property
def hass_device_info(self):
swv = self.info.firmware_version
if self.info.hardware_version:
swv = f'{swv}@{self.info.hardware_version}'
updater = self.data.get('updater')
if updater and updater not in ['none']:
swv = f'{swv} ({updater})'
return {
'identifiers': {(DOMAIN, self.info.unique_id)},
'name': self.info.name,
'model': self.model,
'manufacturer': (self.model or 'Xiaomi').split('.', 1)[0],
'sw_version': swv,
'suggested_area': self.info.room_name,
'configuration_url': f'https://home.miot-spec.com/s/{self.model}',
}

@property
def customizes(self):
cfg = {}
Expand Down Expand Up @@ -230,9 +249,9 @@ def init_converters(self):
for prop in self.spec.get_properties(*pls):
self.converters.append(MiotPropConv(prop, d))

def add_entity(self, entity: 'BaseEntity'):
def add_entity(self, entity: 'XEntity'):
if entity not in self.entities:
self.entities.append(entity)
self.entities[entity.unique_id] = entity

def add_listener(self, handler: Callable):
if handler not in self.listeners:
Expand All @@ -243,8 +262,6 @@ def remove_listener(self, handler: Callable):
self.listeners.remove(handler)

def dispatch(self, data: dict):
if self.converters: # TODO
_LOGGER.warning('%s: Device dispatch data: %s', self.name_model, data)
for handler in self.listeners:
handler(data)

Expand Down Expand Up @@ -349,7 +366,9 @@ async def update_miot_status(
self.name_model, exc, mapping,
)

self.data['updater'] = self.miot_results.updater
if results:
self.data['miot_results'] = results
self.dispatch(self.decode(results))
return self.miot_results

Expand Down
37 changes: 31 additions & 6 deletions custom_components/xiaomi_miot/core/hass_entity.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import logging
from typing import TYPE_CHECKING, Callable

from homeassistant.helpers.entity import Entity, DeviceInfo
from homeassistant.helpers.entity import Entity

from .miot_spec import MiotService, MiotProperty
from .miot_spec import MiotService, MiotProperty, MiotAction

if TYPE_CHECKING:
from .device import Device
Expand All @@ -24,17 +24,26 @@ def __init__(self, device: 'Device', conv: 'BaseConv'):
self.hass = device.hass
self.conv = conv
attr = conv.attr
if isinstance(attr, MiotProperty):

if isinstance(attr, (MiotProperty, MiotAction)):
self.attr = attr.full_name
self._attr_translation_key = attr.friendly_name
self.entity_id = attr.generate_entity_id(self, conv.domain)
self._attr_name = attr.friendly_desc
self._attr_translation_key = attr.friendly_name
elif isinstance(attr, MiotService):
self.attr = attr.name
self._attr_translation_key = attr.name
self.entity_id = attr.generate_entity_id(self, conv.domain)
self._attr_name = attr.friendly_desc
self._attr_translation_key = attr.name
else:
self.attr = attr
prefix = device.spec.generate_entity_id(self)
self.entity_id = f'{prefix}_{attr}'
self._attr_name = attr.replace('_', '').title()
self._attr_translation_key = attr
self.listen_attrs: set = {self.attr}
self._attr_unique_id = f'{device.info.unique_id}-{convert_unique_id(conv)}'
self._attr_device_info = self.device.hass_device_info

self.on_init()

Expand All @@ -46,7 +55,15 @@ def on_init(self):
"""Run on class init."""

def on_device_update(self, data: dict):
pass
state_change = False
_LOGGER.info('%s: Device updated: %s', self.entity_id, [self.listen_attrs, data])

if self.listen_attrs & data.keys():
self.set_state(data)
state_change = True

if state_change and self.added:
self._async_write_ha_state()

def get_state(self) -> dict:
"""Run before entity remove if entity is subclass from RestoreEntity."""
Expand All @@ -57,7 +74,15 @@ def set_state(self, data: dict):
self._attr_state = data.get(self.attr)

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

async def async_will_remove_from_hass(self) -> None:
self.device.remove_listener(self.on_device_update)


def convert_unique_id(conv: 'BaseConv'):
attr = conv.attr
if isinstance(attr, (MiotService, MiotProperty, MiotAction)):
return attr.unique_name
return attr
21 changes: 21 additions & 0 deletions custom_components/xiaomi_miot/core/hass_entry.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import logging
from typing import TYPE_CHECKING, Optional
from homeassistant.core import HomeAssistant
from homeassistant.const import CONF_USERNAME
from homeassistant.config_entries import ConfigEntry
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

_LOGGER = logging.getLogger(__package__)

class HassEntry:
ALL: dict[str, 'HassEntry'] = {}
cloud: MiotCloud = None
Expand Down Expand Up @@ -52,6 +56,23 @@ async def new_device(self, device_info: dict, cloud: Optional[MiotCloud] = None)

def new_adder(self, domain, adder: AddEntitiesCallback):
self.adders[domain] = adder
_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.entities[key] = entity
adder([entity], update_before_add=False)
_LOGGER.info('New entity: %s', entity)

return self

async def get_cloud(self, check=False, login=False):
Expand Down

0 comments on commit da15f08

Please sign in to comment.