Skip to content

Commit

Permalink
⬆ new version v1.0.0 (#1989)
Browse files Browse the repository at this point in the history
  • Loading branch information
al-one authored Dec 3, 2024
1 parent f5e743e commit 8a16266
Show file tree
Hide file tree
Showing 36 changed files with 2,952 additions and 1,855 deletions.
1,113 changes: 111 additions & 1,002 deletions custom_components/xiaomi_miot/__init__.py

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion custom_components/xiaomi_miot/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
DOMAIN,
CONF_MODEL,
XIAOMI_CONFIG_SCHEMA as PLATFORM_SCHEMA, # noqa: F401
HassEntry,
MiotEntity,
async_setup_config_entry,
bind_services_to_entries,
Expand All @@ -28,6 +29,7 @@


async def async_setup_entry(hass, config_entry, async_add_entities):
HassEntry.init(hass, config_entry).new_adder(ENTITY_DOMAIN, async_add_entities)
await async_setup_config_entry(hass, config_entry, async_setup_platform, async_add_entities, ENTITY_DOMAIN)


Expand All @@ -53,7 +55,7 @@ class MiotAlarmEntity(MiotEntity, AlarmControlPanelEntity):
def __init__(self, config, miot_service: MiotService):
super().__init__(miot_service, config=config, logger=_LOGGER)
self._attr_code_arm_required = False
self._is_mgl03 = self._model == 'lumi.gateway.mgl03'
self._is_mgl03 = self.model == 'lumi.gateway.mgl03'
self._prop_mode = miot_service.get_property('arming_mode')
if self._prop_mode:
if self._prop_mode.list_value('home_arming') is not None:
Expand Down
86 changes: 30 additions & 56 deletions custom_components/xiaomi_miot/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,33 @@
import time
import json
from datetime import datetime
from functools import cached_property

from homeassistant.const import (
STATE_OFF,
STATE_ON,
STATE_UNKNOWN,
STATE_OFF,
STATE_ON,
STATE_UNKNOWN,
)
from homeassistant.components.binary_sensor import (
DOMAIN as ENTITY_DOMAIN,
BinarySensorEntity,
BinarySensorEntity as BaseEntity,
BinarySensorDeviceClass,
)
from homeassistant.helpers.restore_state import RestoreEntity

from . import (
DOMAIN,
CONF_MODEL,
XIAOMI_CONFIG_SCHEMA as PLATFORM_SCHEMA, # noqa: F401
HassEntry,
XEntity,
MiotToggleEntity,
MiotPropertySubEntity,
ToggleSubEntity,
async_setup_config_entry,
bind_services_to_entries,
)
from .core.miot_spec import (
MiotSpec,
MiotService,
MiotProperty,
)
from .core.xiaomi_cloud import MiotCloud
from .core.utils import local_zone
Expand All @@ -40,6 +41,7 @@


async def async_setup_entry(hass, config_entry, async_add_entities):
HassEntry.init(hass, config_entry).new_adder(ENTITY_DOMAIN, async_add_entities)
await async_setup_config_entry(hass, config_entry, async_setup_platform, async_add_entities, ENTITY_DOMAIN)


Expand Down Expand Up @@ -82,7 +84,27 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
bind_services_to_entries(hass, SERVICE_TO_METHOD)


class MiotBinarySensorEntity(MiotToggleEntity, BinarySensorEntity):
class BinarySensorEntity(XEntity, BaseEntity, RestoreEntity):
def set_state(self, data: dict):
val = data.get(self.attr)
if val is None:
return
if self.custom_reverse:
self._attr_extra_state_attributes['reverse_state'] = True
val = not val
self._attr_is_on = val

def get_state(self) -> dict:
return {self.attr: not self._attr_is_on if self.custom_reverse else self._attr_is_on}

@cached_property
def custom_reverse(self):
return self.custom_config_bool('reverse_state', False)

XEntity.CLS[ENTITY_DOMAIN] = BinarySensorEntity


class MiotBinarySensorEntity(MiotToggleEntity, BaseEntity):
def __init__(self, config, miot_service: MiotService, **kwargs):
kwargs.setdefault('logger', _LOGGER)
super().__init__(miot_service, config=config, **kwargs)
Expand Down Expand Up @@ -127,10 +149,6 @@ async def async_added_to_hass(self):
if rev is not None:
self._vars['reverse_state'] = rev

async def async_update_for_main_entity(self):
await super().async_update_for_main_entity()
self._update_sub_entities(['illumination', 'no_motion_duration'], domain='sensor')

@property
def is_on(self):
ret = self._state
Expand Down Expand Up @@ -196,7 +214,6 @@ async def async_update_for_main_entity(self):
if self.custom_config_bool('use_ble_object', True):
await self.async_update_ble_data()
await super().async_update_for_main_entity()
self._update_sub_entities(['illumination', 'no_motion_duration'], domain='sensor')

async def async_update_ble_data(self):
did = self.miot_did
Expand Down Expand Up @@ -287,43 +304,6 @@ def __init__(self, config, miot_service: MiotService):
self._prop_state.name if self._prop_state else 'status',
)

async def async_update(self):
await super().async_update()
if not self._available:
return
from .fan import MiotModesSubEntity
add_fans = self._add_entities.get('fan')
pls = self._miot_service.get_properties(
'mode', 'washing_strength', 'nozzle_position', 'heat_level',
)
seat = self._miot_service.spec.get_service('seat')
if seat:
prop = seat.get_property('heat_level')
if prop:
pls.append(prop)
else:
self._update_sub_entities(
['heating', 'deodorization'],
[seat],
domain='switch',
)
for p in pls:
if not p.value_list and not p.value_range:
continue
if p.name in self._subs:
self._subs[p.name].update()
elif add_fans:
opt = None
if p.name in ['heat_level']:
opt = {
'power_property': p.service.bool_property('heating'),
}
self._subs[p.name] = MiotModesSubEntity(self, p, opt)
add_fans([self._subs[p.name]], update_before_add=True)

if self._prop_power:
self._update_sub_entities(self._prop_power, None, 'switch')

@property
def icon(self):
return 'mdi:toilet'
Expand Down Expand Up @@ -372,9 +352,3 @@ async def async_update(self):
adt[self._prop_state.full_name] = self._state
if adt:
await self.async_update_attrs(adt)


class MiotBinarySensorSubEntity(MiotPropertySubEntity, ToggleSubEntity, BinarySensorEntity):
def __init__(self, parent, miot_property: MiotProperty, option=None):
ToggleSubEntity.__init__(self, parent, miot_property.full_name, option)
super().__init__(parent, miot_property, option, domain=ENTITY_DOMAIN)
57 changes: 25 additions & 32 deletions custom_components/xiaomi_miot/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,19 @@

from homeassistant.components.button import (
DOMAIN as ENTITY_DOMAIN,
ButtonEntity,
ButtonEntity as BaseEntity,
)

from . import (
DOMAIN,
CONF_MODEL,
XIAOMI_CONFIG_SCHEMA as PLATFORM_SCHEMA, # noqa: F401
MiotEntity,
HassEntry,
XEntity,
MiotPropertySubEntity,
BaseSubEntity,
async_setup_config_entry,
bind_services_to_entries,
)
from .core.miot_spec import (
MiotSpec,
MiotService,
MiotProperty,
MiotAction,
)
Expand All @@ -30,37 +27,33 @@


async def async_setup_entry(hass, config_entry, async_add_entities):
HassEntry.init(hass, config_entry).new_adder(ENTITY_DOMAIN, async_add_entities)
await async_setup_config_entry(hass, config_entry, async_setup_platform, async_add_entities, ENTITY_DOMAIN)


async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
hass.data.setdefault(DATA_KEY, {})
hass.data[DOMAIN]['add_entities'][ENTITY_DOMAIN] = async_add_entities
config['hass'] = hass
model = str(config.get(CONF_MODEL) or '')
spec = hass.data[DOMAIN]['miot_specs'].get(model)
entities = []
if isinstance(spec, MiotSpec):
for srv in spec.get_services('none_service'):
if not srv.get_property('none_property'):
continue
entities.append(MiotButtonEntity(config, srv))
for entity in entities:
hass.data[DOMAIN]['entities'][entity.unique_id] = entity
async_add_entities(entities, update_before_add=True)
bind_services_to_entries(hass, SERVICE_TO_METHOD)


class MiotButtonEntity(MiotEntity, ButtonEntity):
def __init__(self, config, miot_service: MiotService):
super().__init__(miot_service, config=config, logger=_LOGGER)

def press(self) -> None:
"""Press the button."""
raise NotImplementedError()


class MiotButtonSubEntity(MiotPropertySubEntity, ButtonEntity):
class ButtonEntity(XEntity, BaseEntity):
def on_init(self):
self._attr_available = True
if des := getattr(self.conv, 'description', None):
self._attr_name = f'{self._attr_name} {des}'

def set_state(self, data: dict):
pass

async def async_press(self):
pms = getattr(self.conv, 'value', None)
if self._miot_action and self._miot_action.ins:
pms = self.custom_config_list('action_params', pms)
await self.device.async_write({self.attr: pms})

XEntity.CLS[ENTITY_DOMAIN] = ButtonEntity


class MiotButtonSubEntity(MiotPropertySubEntity, BaseEntity):
def __init__(self, parent, miot_property: MiotProperty, value, option=None):
super().__init__(parent, miot_property, option, domain=ENTITY_DOMAIN)
self._miot_property_value = value
Expand All @@ -87,7 +80,7 @@ def press(self):
return self.set_parent_property(self._miot_property_value)


class MiotButtonActionSubEntity(BaseSubEntity, ButtonEntity):
class MiotButtonActionSubEntity(BaseSubEntity, BaseEntity):
def __init__(self, parent, miot_action: MiotAction, option=None):
self._miot_action = miot_action
super().__init__(parent, miot_action.full_name, option, domain=ENTITY_DOMAIN)
Expand Down Expand Up @@ -116,7 +109,7 @@ def press(self):
return self.call_parent('call_action', self._miot_action, pms)


class ButtonSubEntity(ButtonEntity, BaseSubEntity):
class ButtonSubEntity(BaseEntity, BaseSubEntity):
def __init__(self, parent, attr, option=None):
BaseSubEntity.__init__(self, parent, attr, option)
self._available = True
Expand Down
6 changes: 4 additions & 2 deletions custom_components/xiaomi_miot/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
DOMAIN,
CONF_MODEL,
XIAOMI_CONFIG_SCHEMA as PLATFORM_SCHEMA, # noqa: F401
HassEntry,
MiotToggleEntity,
BaseSubEntity,
MiotCloud,
Expand All @@ -49,6 +50,7 @@


async def async_setup_entry(hass, config_entry, async_add_entities):
HassEntry.init(hass, config_entry).new_adder(ENTITY_DOMAIN, async_add_entities)
await async_setup_config_entry(hass, config_entry, async_setup_platform, async_add_entities, ENTITY_DOMAIN)


Expand Down Expand Up @@ -181,7 +183,7 @@ def __init__(self, hass: HomeAssistant, config: dict, miot_service: MiotService)
self._supported_features |= CameraEntityFeature.ON_OFF
if miot_service:
self._prop_motion_tracking = miot_service.bool_property('motion_detection', 'motion_tracking')
self._is_doorbell = miot_service.name in ['video_doorbell'] or '.lock.' in self._model
self._is_doorbell = miot_service.name in ['video_doorbell'] or '.lock.' in self.model

async def async_added_to_hass(self):
await super().async_added_to_hass()
Expand Down Expand Up @@ -279,7 +281,7 @@ async def async_update(self):
api = mic.get_api_by_host('business.smartcamera.api.io.mi.com', 'common/app/get/eventlist')
rqd = {
'did': self.miot_did,
'model': self._model,
'model': self.model,
'doorBell': self._is_doorbell,
'eventType': 'Default',
'needMerge': True,
Expand Down
14 changes: 2 additions & 12 deletions custom_components/xiaomi_miot/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
DOMAIN,
CONF_MODEL,
XIAOMI_CONFIG_SCHEMA as PLATFORM_SCHEMA, # noqa: F401
HassEntry,
MiotEntity,
MiotToggleEntity,
async_setup_config_entry,
Expand All @@ -55,6 +56,7 @@


async def async_setup_entry(hass, config_entry, async_add_entities):
HassEntry.init(hass, config_entry).new_adder(ENTITY_DOMAIN, async_add_entities)
await async_setup_config_entry(hass, config_entry, async_setup_platform, async_add_entities, ENTITY_DOMAIN)


Expand Down Expand Up @@ -252,18 +254,6 @@ async def async_update(self):
add_fans([self._subs[des]], update_before_add=True)

add_switches = self._add_entities.get('switch')
for p in self._miot_service.properties.values():
if not (p.format == 'bool' and p.readable and p.writeable):
continue
if p.name in self._power_modes:
continue
if self._prop_power and self._prop_power.name == p.name:
continue
self._update_sub_entities(p, None, 'switch')

if self._miot_service.name in ['ptc_bath_heater']:
self._update_sub_entities(None, ['light', 'light_bath_heater'], domain='light')

if self._miot_service.get_action('start_wash'):
pnm = 'action_wash'
prop = self._miot_service.get_property('status')
Expand Down
Loading

0 comments on commit 8a16266

Please sign in to comment.