Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 73 additions & 3 deletions custom_components/xiaomi_home/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,17 @@
import logging
from typing import Optional

import voluptuous as vol

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.components import persistent_notification
from homeassistant.helpers import device_registry, entity_registry
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import (
config_validation as cv,
device_registry,
entity_registry,
)

from .miot.common import slugify_did
from .miot.miot_storage import (
Expand All @@ -61,13 +68,21 @@
MIoTSpecInstance, MIoTSpecParser, MIoTSpecService)
from .miot.const import (
DEFAULT_INTEGRATION_LANGUAGE, DOMAIN, SUPPORTED_PLATFORMS)
from .miot.miot_error import MIoTOauthError
from .miot.miot_error import MIoTClientError, MIoTOauthError
from .miot.miot_device import MIoTDevice
from .miot.miot_client import MIoTClient, get_miot_instance_async

_LOGGER = logging.getLogger(__name__)


CALL_ACTION_SCHEMA = vol.Schema({
vol.Required('entity_id'): cv.entity_id,
vol.Required('siid'): vol.All(vol.Coerce(int), vol.Range(min=1, max=9999)),
vol.Required('aiid'): vol.All(vol.Coerce(int), vol.Range(min=1, max=9999)),
vol.Optional('params', default=[]): vol.Any(list, None),
})


async def async_setup(hass: HomeAssistant, hass_config: dict) -> bool:
# pylint: disable=unused-argument
hass.data.setdefault(DOMAIN, {})
Expand All @@ -79,6 +94,61 @@ async def async_setup(hass: HomeAssistant, hass_config: dict) -> bool:
hass.data[DOMAIN].setdefault('entities', {})
for platform in SUPPORTED_PLATFORMS:
hass.data[DOMAIN]['entities'][platform] = []

async def async_handle_call_action(call: ServiceCall) -> None:
"""Handle xiaomi_home.call_action service calls."""
entity_id: str = call.data['entity_id']
siid: int = call.data['siid']
aiid: int = call.data['aiid']
params: list = call.data.get('params') or []

er = entity_registry.async_get(hass)
entry = er.async_get(entity_id)
if entry is None or entry.config_entry_id is None:
raise HomeAssistantError(
f'Entity {entity_id} not found in xiaomi_home')

miot_client: MIoTClient = hass.data[DOMAIN]['miot_clients'].get(
entry.config_entry_id)
if miot_client is None:
raise HomeAssistantError(
f'No MIoT client for config entry {entry.config_entry_id}')

dr = device_registry.async_get(hass)
device_entry = dr.async_get(entry.device_id) if entry.device_id else None
if device_entry is None:
raise HomeAssistantError(
f'No device found for entity {entity_id}')

did = None
for identifier in device_entry.identifiers:
if identifier[0] == DOMAIN:
did_tag = identifier[1]
for d in miot_client.device_list:
if slugify_did(miot_client.cloud_server, d) == did_tag:
did = d
break
break

if did is None:
raise HomeAssistantError(
f'Could not resolve device ID for entity {entity_id}')

in_list = [
{'piid': i + 1, 'value': v} for i, v in enumerate(params)
]

try:
await miot_client.action_async(
did=did, siid=siid, aiid=aiid, in_list=in_list)
except MIoTClientError as err:
raise HomeAssistantError(
f'Action failed: {err}') from err

hass.services.async_register(
DOMAIN, 'call_action', async_handle_call_action,
schema=CALL_ACTION_SCHEMA)

return True


Expand Down
33 changes: 33 additions & 0 deletions custom_components/xiaomi_home/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
call_action:
description: Call a MIoT action on a device.
fields:
entity_id:
description: ID of the entity.
example: vacuum.my_vacuum
required: true
selector:
entity:
integration: xiaomi_home
siid:
description: MIoT service instance ID.
example: 2
required: true
selector:
number:
min: 1
max: 9999
mode: box
aiid:
description: MIoT action instance ID.
example: 13
required: true
selector:
number:
min: 1
max: 9999
mode: box
params:
description: Action input parameters.
example: "['{\"room\":[[3,4,5]]}']"
selector:
object: