206 lines
6.5 KiB
Python
206 lines
6.5 KiB
Python
"""Implement the Yandex Smart Home toggles capabilities."""
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC
|
|
import logging
|
|
from typing import Any
|
|
|
|
from homeassistant.components import cover, fan, media_player, vacuum
|
|
from homeassistant.const import ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES
|
|
from homeassistant.core import HomeAssistant, State
|
|
|
|
from . import const
|
|
from .capability import PREFIX_CAPABILITIES, AbstractCapability, register_capability
|
|
from .helpers import Config, RequestData
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
CAPABILITIES_TOGGLE = PREFIX_CAPABILITIES + 'toggle'
|
|
|
|
|
|
class ToggleCapability(AbstractCapability, ABC):
|
|
"""Base toggle functionality.
|
|
|
|
https://yandex.ru/dev/dialogs/alice/doc/smart-home/concepts/toggle-docpage/
|
|
"""
|
|
|
|
type = CAPABILITIES_TOGGLE
|
|
|
|
def parameters(self) -> dict[str, Any]:
|
|
"""Return parameters for a devices request."""
|
|
return {
|
|
'instance': self.instance
|
|
}
|
|
|
|
|
|
@register_capability
|
|
class MuteCapability(ToggleCapability):
|
|
"""Mute and unmute functionality."""
|
|
|
|
instance = const.TOGGLE_INSTANCE_MUTE
|
|
|
|
def __init__(self, hass: HomeAssistant, config: Config, state: State):
|
|
super().__init__(hass, config, state)
|
|
|
|
self.retrievable = media_player.ATTR_MEDIA_VOLUME_MUTED in self.state.attributes
|
|
|
|
def supported(self) -> bool:
|
|
"""Test if capability is supported."""
|
|
features = self.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
|
|
|
if self.state.domain == media_player.DOMAIN:
|
|
if features & media_player.MediaPlayerEntityFeature.VOLUME_MUTE:
|
|
return True
|
|
|
|
if const.MEDIA_PLAYER_FEATURE_VOLUME_MUTE in self.entity_config.get(const.CONF_FEATURES, []):
|
|
return True
|
|
|
|
return False
|
|
|
|
def get_value(self) -> bool:
|
|
"""Return the state value of this capability for this entity."""
|
|
muted = self.state.attributes.get(media_player.ATTR_MEDIA_VOLUME_MUTED)
|
|
|
|
return bool(muted)
|
|
|
|
async def set_state(self, data: RequestData, state: dict[str, Any]):
|
|
"""Set device state."""
|
|
await self.hass.services.async_call(
|
|
media_player.DOMAIN,
|
|
media_player.SERVICE_VOLUME_MUTE, {
|
|
ATTR_ENTITY_ID: self.state.entity_id,
|
|
media_player.ATTR_MEDIA_VOLUME_MUTED: state['value']
|
|
},
|
|
blocking=True,
|
|
context=data.context
|
|
)
|
|
|
|
|
|
class PauseCapability(ToggleCapability, ABC):
|
|
"""Pause and unpause functionality."""
|
|
|
|
instance = const.TOGGLE_INSTANCE_PAUSE
|
|
|
|
|
|
@register_capability
|
|
class PauseCapabilityMediaPlayer(PauseCapability):
|
|
def supported(self) -> bool:
|
|
"""Test if capability is supported."""
|
|
features = self.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
|
|
|
if self.state.domain == media_player.DOMAIN:
|
|
if const.MEDIA_PLAYER_FEATURE_PLAY_PAUSE in self.entity_config.get(const.CONF_FEATURES, []):
|
|
return True
|
|
|
|
if features & media_player.MediaPlayerEntityFeature.PAUSE and \
|
|
features & media_player.MediaPlayerEntityFeature.PLAY:
|
|
return True
|
|
|
|
return False
|
|
|
|
def get_value(self) -> bool:
|
|
"""Return the state value of this capability for this entity."""
|
|
return bool(self.state.state != media_player.STATE_PLAYING)
|
|
|
|
async def set_state(self, data: RequestData, state: dict[str, Any]):
|
|
"""Set device state."""
|
|
if state['value']:
|
|
service = media_player.SERVICE_MEDIA_PAUSE
|
|
else:
|
|
service = media_player.SERVICE_MEDIA_PLAY
|
|
|
|
await self.hass.services.async_call(
|
|
media_player.DOMAIN,
|
|
service, {
|
|
ATTR_ENTITY_ID: self.state.entity_id
|
|
},
|
|
blocking=True,
|
|
context=data.context
|
|
)
|
|
|
|
|
|
@register_capability
|
|
class PauseCapabilityCover(PauseCapability):
|
|
retrievable = False
|
|
|
|
def supported(self) -> bool:
|
|
"""Test if capability is supported."""
|
|
features = self.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
|
|
|
return self.state.domain == cover.DOMAIN and features & cover.CoverEntityFeature.STOP
|
|
|
|
def get_value(self) -> bool:
|
|
"""Return the state value of this capability for this entity."""
|
|
return False
|
|
|
|
async def set_state(self, data: RequestData, state: dict[str, Any]):
|
|
"""Set device state."""
|
|
await self.hass.services.async_call(
|
|
cover.DOMAIN,
|
|
cover.SERVICE_STOP_COVER, {
|
|
ATTR_ENTITY_ID: self.state.entity_id
|
|
},
|
|
blocking=True,
|
|
context=data.context
|
|
)
|
|
|
|
|
|
@register_capability
|
|
class PauseCapabilityVacuum(PauseCapability):
|
|
instance = const.TOGGLE_INSTANCE_PAUSE
|
|
|
|
def supported(self) -> bool:
|
|
"""Test if capability is supported."""
|
|
features = self.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
|
|
|
return self.state.domain == vacuum.DOMAIN and features & vacuum.VacuumEntityFeature.PAUSE
|
|
|
|
def get_value(self) -> bool:
|
|
"""Return the state value of this capability for this entity."""
|
|
return self.state.state == vacuum.STATE_PAUSED
|
|
|
|
async def set_state(self, data: RequestData, state: dict[str, Any]):
|
|
"""Set device state."""
|
|
if state['value']:
|
|
service = vacuum.SERVICE_PAUSE
|
|
else:
|
|
service = vacuum.SERVICE_START
|
|
|
|
await self.hass.services.async_call(
|
|
vacuum.DOMAIN,
|
|
service, {
|
|
ATTR_ENTITY_ID: self.state.entity_id
|
|
},
|
|
blocking=True,
|
|
context=data.context
|
|
)
|
|
|
|
|
|
@register_capability
|
|
class OscillationCapability(ToggleCapability):
|
|
"""Oscillation functionality."""
|
|
|
|
instance = const.TOGGLE_INSTANCE_OSCILLATION
|
|
|
|
def supported(self) -> bool:
|
|
"""Test if capability is supported."""
|
|
features = self.state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
|
|
|
return self.state.domain == fan.DOMAIN and features & fan.FanEntityFeature.OSCILLATE
|
|
|
|
def get_value(self) -> bool:
|
|
"""Return the state value of this capability for this entity."""
|
|
return bool(self.state.attributes.get(fan.ATTR_OSCILLATING))
|
|
|
|
async def set_state(self, data: RequestData, state: dict[str, Any]):
|
|
"""Set device state."""
|
|
await self.hass.services.async_call(
|
|
fan.DOMAIN,
|
|
fan.SERVICE_OSCILLATE, {
|
|
ATTR_ENTITY_ID: self.state.entity_id,
|
|
fan.ATTR_OSCILLATING: state['value']
|
|
},
|
|
blocking=True,
|
|
context=data.context
|
|
)
|