Files
2024-01-11 15:10:51 +03:00

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
)