mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 01:38:02 +00:00
Merge pull request #1485 from MartinHjelmare/refactor-scene-reproduce_state
Refactor reproduce_state for scene component
This commit is contained in:
commit
47c4f66886
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Component to interface with a alarm control panel.
|
||||
Component to interface with an alarm control panel.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/alarm_control_panel/
|
||||
@ -9,7 +9,7 @@ import os
|
||||
|
||||
from homeassistant.components import verisure
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER,
|
||||
ATTR_CODE, ATTR_CODE_FORMAT, ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER,
|
||||
SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY)
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.helpers.entity import Entity
|
||||
@ -32,9 +32,6 @@ SERVICE_TO_METHOD = {
|
||||
SERVICE_ALARM_TRIGGER: 'alarm_trigger'
|
||||
}
|
||||
|
||||
ATTR_CODE = 'code'
|
||||
ATTR_CODE_FORMAT = 'code_format'
|
||||
|
||||
ATTR_TO_PROPERTY = [
|
||||
ATTR_CODE,
|
||||
ATTR_CODE_FORMAT
|
||||
@ -149,5 +146,5 @@ class AlarmControlPanel(Entity):
|
||||
"""Return the state attributes."""
|
||||
state_attr = {
|
||||
ATTR_CODE_FORMAT: self.code_format,
|
||||
}
|
||||
}
|
||||
return state_attr
|
||||
|
@ -13,8 +13,8 @@ from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from homeassistant.const import (
|
||||
STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN, SERVICE_LOCK, SERVICE_UNLOCK,
|
||||
ATTR_ENTITY_ID)
|
||||
ATTR_CODE, ATTR_CODE_FORMAT, ATTR_ENTITY_ID, STATE_LOCKED, STATE_UNLOCKED,
|
||||
STATE_UNKNOWN, SERVICE_LOCK, SERVICE_UNLOCK)
|
||||
from homeassistant.components import (group, verisure, wink)
|
||||
|
||||
DOMAIN = 'lock'
|
||||
@ -25,10 +25,6 @@ ENTITY_ID_ALL_LOCKS = group.ENTITY_ID_FORMAT.format('all_locks')
|
||||
|
||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||
|
||||
ATTR_LOCKED = "locked"
|
||||
ATTR_CODE = 'code'
|
||||
ATTR_CODE_FORMAT = 'code_format'
|
||||
|
||||
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
|
||||
|
||||
# Maps discovered services to their platforms
|
||||
|
@ -8,10 +8,10 @@ import logging
|
||||
|
||||
from homeassistant.components.verisure import HUB as hub
|
||||
from homeassistant.components.lock import LockDevice
|
||||
from homeassistant.const import STATE_LOCKED, STATE_UNKNOWN, STATE_UNLOCKED
|
||||
from homeassistant.const import (
|
||||
ATTR_CODE, STATE_LOCKED, STATE_UNKNOWN, STATE_UNLOCKED)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
ATTR_CODE = 'code'
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
@ -22,7 +22,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
locks.extend([
|
||||
VerisureDoorlock(device_id)
|
||||
for device_id in hub.lock_status.keys()
|
||||
])
|
||||
])
|
||||
add_devices(locks)
|
||||
|
||||
|
||||
|
@ -108,9 +108,10 @@ ATTR_TO_PROPERTY = [
|
||||
|
||||
|
||||
def is_on(hass, entity_id=None):
|
||||
"""Return true if specified media player entity_id is on.
|
||||
"""
|
||||
Return true if specified media player entity_id is on.
|
||||
|
||||
Will check all media player if no entity_id specified.
|
||||
Check all media player if no entity_id specified.
|
||||
"""
|
||||
entity_ids = [entity_id] if entity_id else hass.states.entity_ids(DOMAIN)
|
||||
return any(not hass.states.is_state(entity_id, STATE_OFF)
|
||||
@ -118,19 +119,19 @@ def is_on(hass, entity_id=None):
|
||||
|
||||
|
||||
def turn_on(hass, entity_id=None):
|
||||
"""Will turn on specified media player or all."""
|
||||
"""Turn on specified media player or all."""
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
hass.services.call(DOMAIN, SERVICE_TURN_ON, data)
|
||||
|
||||
|
||||
def turn_off(hass, entity_id=None):
|
||||
"""Will turn off specified media player or all."""
|
||||
"""Turn off specified media player or all."""
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
|
||||
|
||||
|
||||
def toggle(hass, entity_id=None):
|
||||
"""Will toggle specified media player or all."""
|
||||
"""Toggle specified media player or all."""
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
hass.services.call(DOMAIN, SERVICE_TOGGLE, data)
|
||||
|
||||
@ -148,7 +149,7 @@ def volume_down(hass, entity_id=None):
|
||||
|
||||
|
||||
def mute_volume(hass, mute, entity_id=None):
|
||||
"""Send the media player the command for volume down."""
|
||||
"""Send the media player the command for muting the volume."""
|
||||
data = {ATTR_MEDIA_VOLUME_MUTED: mute}
|
||||
|
||||
if entity_id:
|
||||
@ -158,7 +159,7 @@ def mute_volume(hass, mute, entity_id=None):
|
||||
|
||||
|
||||
def set_volume_level(hass, volume, entity_id=None):
|
||||
"""Send the media player the command for volume down."""
|
||||
"""Send the media player the command for setting the volume."""
|
||||
data = {ATTR_MEDIA_VOLUME_LEVEL: volume}
|
||||
|
||||
if entity_id:
|
||||
@ -180,7 +181,7 @@ def media_play(hass, entity_id=None):
|
||||
|
||||
|
||||
def media_pause(hass, entity_id=None):
|
||||
"""Send the media player the command for play/pause."""
|
||||
"""Send the media player the command for pause."""
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
|
||||
hass.services.call(DOMAIN, SERVICE_MEDIA_PAUSE, data)
|
||||
|
||||
@ -206,7 +207,8 @@ def media_seek(hass, position, entity_id=None):
|
||||
|
||||
def play_media(hass, media_type, media_id, entity_id=None):
|
||||
"""Send the media player the command for playing media."""
|
||||
data = {"media_type": media_type, "media_id": media_id}
|
||||
data = {ATTR_MEDIA_CONTENT_TYPE: media_type,
|
||||
ATTR_MEDIA_CONTENT_ID: media_id}
|
||||
|
||||
if entity_id:
|
||||
data[ATTR_ENTITY_ID] = entity_id
|
||||
@ -297,8 +299,8 @@ def setup(hass, config):
|
||||
|
||||
def play_media_service(service):
|
||||
"""Play specified media_id on the media player."""
|
||||
media_type = service.data.get('media_type')
|
||||
media_id = service.data.get('media_id')
|
||||
media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE)
|
||||
media_id = service.data.get(ATTR_MEDIA_CONTENT_ID)
|
||||
|
||||
if media_type is None:
|
||||
return
|
||||
@ -320,10 +322,12 @@ def setup(hass, config):
|
||||
|
||||
|
||||
class MediaPlayerDevice(Entity):
|
||||
"""An abstract class for media player devices."""
|
||||
"""ABC for media player devices."""
|
||||
|
||||
# pylint: disable=too-many-public-methods,no-self-use
|
||||
|
||||
# Implement these for your media player
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""State of the player."""
|
||||
@ -366,37 +370,37 @@ class MediaPlayerDevice(Entity):
|
||||
|
||||
@property
|
||||
def media_artist(self):
|
||||
"""Artist of current playing media (Music track only)."""
|
||||
"""Artist of current playing media, music track only."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def media_album_name(self):
|
||||
"""Album name of current playing media (Music track only)."""
|
||||
"""Album name of current playing media, music track only."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def media_album_artist(self):
|
||||
"""Album artist of current playing media (Music track only)."""
|
||||
"""Album artist of current playing media, music track only."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def media_track(self):
|
||||
"""Track number of current playing media (Music track only)."""
|
||||
"""Track number of current playing media, music track only."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def media_series_title(self):
|
||||
"""The title of the series of current playing media (TV Show only)."""
|
||||
"""Title of series of current playing media, TV show only."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def media_season(self):
|
||||
"""Season of current playing media (TV Show only)."""
|
||||
"""Season of current playing media, TV show only."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def media_episode(self):
|
||||
"""Episode of current playing media (TV Show only)."""
|
||||
"""Episode of current playing media, TV show only."""
|
||||
return None
|
||||
|
||||
@property
|
||||
@ -421,7 +425,7 @@ class MediaPlayerDevice(Entity):
|
||||
|
||||
@property
|
||||
def supported_media_commands(self):
|
||||
"""Flag of media commands that are supported."""
|
||||
"""Flag media commands that are supported."""
|
||||
return 0
|
||||
|
||||
def turn_on(self):
|
||||
@ -508,17 +512,17 @@ class MediaPlayerDevice(Entity):
|
||||
self.turn_off()
|
||||
|
||||
def volume_up(self):
|
||||
"""volume_up media player."""
|
||||
"""Turn volume up for media player."""
|
||||
if self.volume_level < 1:
|
||||
self.set_volume_level(min(1, self.volume_level + .1))
|
||||
|
||||
def volume_down(self):
|
||||
"""volume_down media player."""
|
||||
"""Turn volume down for media player."""
|
||||
if self.volume_level > 0:
|
||||
self.set_volume_level(max(0, self.volume_level - .1))
|
||||
|
||||
def media_play_pause(self):
|
||||
"""media_play_pause media player."""
|
||||
"""Play or pause the media player."""
|
||||
if self.state == STATE_PLAYING:
|
||||
self.media_pause()
|
||||
else:
|
||||
@ -526,7 +530,7 @@ class MediaPlayerDevice(Entity):
|
||||
|
||||
@property
|
||||
def entity_picture(self):
|
||||
"""Return the image of the media playing."""
|
||||
"""Return image of the media playing."""
|
||||
return None if self.state == STATE_OFF else self.media_image_url
|
||||
|
||||
@property
|
||||
|
@ -43,7 +43,6 @@ REQUIREMENTS = []
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Setup the universal media players."""
|
||||
if not validate_config(config):
|
||||
@ -200,7 +199,7 @@ class UniversalMediaPlayer(MediaPlayerDevice):
|
||||
|
||||
@property
|
||||
def master_state(self):
|
||||
"""Get the master state from entity or none."""
|
||||
"""Return the master state for entity or None."""
|
||||
if CONF_STATE in self._attrs:
|
||||
master_state = self._entity_lkp(self._attrs[CONF_STATE][0],
|
||||
self._attrs[CONF_STATE][1])
|
||||
@ -324,7 +323,7 @@ class UniversalMediaPlayer(MediaPlayerDevice):
|
||||
|
||||
@property
|
||||
def supported_media_commands(self):
|
||||
"""Flag of media commands that are supported."""
|
||||
"""Flag media commands that are supported."""
|
||||
flags = self._child_attr(ATTR_SUPPORTED_MEDIA_COMMANDS) or 0
|
||||
|
||||
if SERVICE_TURN_ON in self._cmds:
|
||||
@ -345,7 +344,7 @@ class UniversalMediaPlayer(MediaPlayerDevice):
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Extra attributes a device wants to expose."""
|
||||
"""Return device specific state attributes."""
|
||||
active_child = self._child_state
|
||||
return {ATTR_ACTIVE_CHILD: active_child.entity_id} \
|
||||
if active_child else {}
|
||||
@ -391,23 +390,24 @@ class UniversalMediaPlayer(MediaPlayerDevice):
|
||||
|
||||
def play_media(self, media_type, media_id):
|
||||
"""Play a piece of media."""
|
||||
data = {'media_type': media_type, 'media_id': media_id}
|
||||
data = {ATTR_MEDIA_CONTENT_TYPE: media_type,
|
||||
ATTR_MEDIA_CONTENT_ID: media_id}
|
||||
self._call_service(SERVICE_PLAY_MEDIA, data)
|
||||
|
||||
def volume_up(self):
|
||||
"""Volume up media player."""
|
||||
"""Turn volume up for media player."""
|
||||
self._call_service(SERVICE_VOLUME_UP, allow_override=True)
|
||||
|
||||
def volume_down(self):
|
||||
"""Volume down media player."""
|
||||
"""Turn volume down for media player."""
|
||||
self._call_service(SERVICE_VOLUME_DOWN, allow_override=True)
|
||||
|
||||
def media_play_pause(self):
|
||||
"""Send play/pause command media player."""
|
||||
"""Play or pause the media player."""
|
||||
self._call_service(SERVICE_MEDIA_PLAY_PAUSE)
|
||||
|
||||
def update(self):
|
||||
"""Event to trigger a state update."""
|
||||
"""Update state in HA."""
|
||||
for child_name in self._children:
|
||||
child_state = self.hass.states.get(child_name)
|
||||
if child_state and child_state.state not in OFF_STATES:
|
||||
|
@ -33,7 +33,7 @@ def activate(hass, entity_id=None):
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
"""Setup the scenes."""
|
||||
"""Setup scenes."""
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# You are not allowed to mutate the original config so make a copy
|
||||
@ -76,9 +76,9 @@ class Scene(Entity):
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state."""
|
||||
"""Return the state of the scene."""
|
||||
return STATE
|
||||
|
||||
def activate(self):
|
||||
"""Activate scene. Tries to get entities into requested state."""
|
||||
"""Activate scene. Try to get entities into requested state."""
|
||||
raise NotImplementedError
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Allows users to set and activate scenes.
|
||||
Allow users to set and activate scenes.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/scene/
|
||||
@ -20,7 +20,6 @@ CONF_ENTITIES = "entities"
|
||||
SceneConfig = namedtuple('SceneConfig', ['name', 'states'])
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Setup home assistant scene entries."""
|
||||
scene_config = config.get("states")
|
||||
@ -83,5 +82,5 @@ class HomeAssistantScene(Scene):
|
||||
}
|
||||
|
||||
def activate(self):
|
||||
"""Activate scene. Tries to get entities into requested state."""
|
||||
"""Activate scene. Try to get entities into requested state."""
|
||||
reproduce_state(self.hass, self.scene_config.states.values(), True)
|
||||
|
@ -102,6 +102,10 @@ ATTR_LOCATION = "location"
|
||||
|
||||
ATTR_BATTERY_LEVEL = "battery_level"
|
||||
|
||||
# For devices which support a code attribute
|
||||
ATTR_CODE = 'code'
|
||||
ATTR_CODE_FORMAT = 'code_format'
|
||||
|
||||
# For devices which support an armed state
|
||||
ATTR_ARMED = "device_armed"
|
||||
|
||||
|
@ -4,24 +4,73 @@ import logging
|
||||
from collections import defaultdict
|
||||
|
||||
import homeassistant.util.dt as dt_util
|
||||
from homeassistant.components.media_player import SERVICE_PLAY_MEDIA
|
||||
from homeassistant.components.media_player import (
|
||||
ATTR_MEDIA_CONTENT_ID, ATTR_MEDIA_CONTENT_TYPE, ATTR_MEDIA_SEEK_POSITION,
|
||||
ATTR_MEDIA_VOLUME_LEVEL, ATTR_MEDIA_VOLUME_MUTED, SERVICE_PLAY_MEDIA)
|
||||
from homeassistant.components.notify import (
|
||||
ATTR_MESSAGE, SERVICE_NOTIFY)
|
||||
from homeassistant.components.sun import (
|
||||
STATE_ABOVE_HORIZON, STATE_BELOW_HORIZON)
|
||||
from homeassistant.components.thermostat import (
|
||||
ATTR_AWAY_MODE, ATTR_FAN, SERVICE_SET_AWAY_MODE, SERVICE_SET_FAN_MODE,
|
||||
SERVICE_SET_TEMPERATURE)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY, SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON, STATE_CLOSED, STATE_LOCKED, STATE_OFF, STATE_ON,
|
||||
STATE_OPEN, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN, STATE_UNLOCKED)
|
||||
ATTR_ENTITY_ID, ATTR_TEMPERATURE, SERVICE_ALARM_ARM_AWAY,
|
||||
SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_DISARM, SERVICE_ALARM_TRIGGER,
|
||||
SERVICE_CLOSE, SERVICE_LOCK, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY,
|
||||
SERVICE_MEDIA_SEEK, SERVICE_MOVE_DOWN, SERVICE_MOVE_UP, SERVICE_OPEN,
|
||||
SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_UNLOCK, SERVICE_VOLUME_MUTE,
|
||||
SERVICE_VOLUME_SET, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
|
||||
STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED, STATE_CLOSED, STATE_LOCKED,
|
||||
STATE_OFF, STATE_ON, STATE_OPEN, STATE_PAUSED, STATE_PLAYING,
|
||||
STATE_UNKNOWN, STATE_UNLOCKED)
|
||||
from homeassistant.core import State
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
GROUP_DOMAIN = 'group'
|
||||
HASS_DOMAIN = 'homeassistant'
|
||||
|
||||
# Update this dict of lists when new services are added to HA.
|
||||
# Each item is a service with a list of required attributes.
|
||||
SERVICE_ATTRIBUTES = {
|
||||
SERVICE_PLAY_MEDIA: [ATTR_MEDIA_CONTENT_TYPE, ATTR_MEDIA_CONTENT_ID],
|
||||
SERVICE_MEDIA_SEEK: [ATTR_MEDIA_SEEK_POSITION],
|
||||
SERVICE_VOLUME_MUTE: [ATTR_MEDIA_VOLUME_MUTED],
|
||||
SERVICE_VOLUME_SET: [ATTR_MEDIA_VOLUME_LEVEL],
|
||||
SERVICE_NOTIFY: [ATTR_MESSAGE],
|
||||
SERVICE_SET_AWAY_MODE: [ATTR_AWAY_MODE],
|
||||
SERVICE_SET_FAN_MODE: [ATTR_FAN],
|
||||
SERVICE_SET_TEMPERATURE: [ATTR_TEMPERATURE],
|
||||
}
|
||||
|
||||
# Update this dict when new services are added to HA.
|
||||
# Each item is a service with a corresponding state.
|
||||
SERVICE_TO_STATE = {
|
||||
SERVICE_TURN_ON: STATE_ON,
|
||||
SERVICE_TURN_OFF: STATE_OFF,
|
||||
SERVICE_MEDIA_PLAY: STATE_PLAYING,
|
||||
SERVICE_MEDIA_PAUSE: STATE_PAUSED,
|
||||
SERVICE_ALARM_ARM_AWAY: STATE_ALARM_ARMED_AWAY,
|
||||
SERVICE_ALARM_ARM_HOME: STATE_ALARM_ARMED_HOME,
|
||||
SERVICE_ALARM_DISARM: STATE_ALARM_DISARMED,
|
||||
SERVICE_ALARM_TRIGGER: STATE_ALARM_TRIGGERED,
|
||||
SERVICE_LOCK: STATE_LOCKED,
|
||||
SERVICE_UNLOCK: STATE_UNLOCKED,
|
||||
SERVICE_CLOSE: STATE_CLOSED,
|
||||
SERVICE_OPEN: STATE_OPEN,
|
||||
SERVICE_MOVE_UP: STATE_OPEN,
|
||||
SERVICE_MOVE_DOWN: STATE_CLOSED,
|
||||
}
|
||||
|
||||
|
||||
# pylint: disable=too-few-public-methods, attribute-defined-outside-init
|
||||
class TrackStates(object):
|
||||
"""Record the time when the with-block is entered.
|
||||
"""
|
||||
Record the time when the with-block is entered.
|
||||
|
||||
Will add all states that have changed since the start time to the return
|
||||
list when with-block is exited.
|
||||
Add all states that have changed since the start time to the return list
|
||||
when with-block is exited.
|
||||
"""
|
||||
|
||||
def __init__(self, hass):
|
||||
@ -40,7 +89,7 @@ class TrackStates(object):
|
||||
|
||||
|
||||
def get_changed_since(states, utc_point_in_time):
|
||||
"""List of states that have been changed since utc_point_in_time."""
|
||||
"""Return list of states that have been changed since utc_point_in_time."""
|
||||
point_in_time = dt_util.strip_microseconds(utc_point_in_time)
|
||||
|
||||
return [state for state in states if state.last_updated >= point_in_time]
|
||||
@ -54,35 +103,36 @@ def reproduce_state(hass, states, blocking=False):
|
||||
to_call = defaultdict(list)
|
||||
|
||||
for state in states:
|
||||
current_state = hass.states.get(state.entity_id)
|
||||
|
||||
if current_state is None:
|
||||
if hass.states.get(state.entity_id) is None:
|
||||
_LOGGER.warning('reproduce_state: Unable to find entity %s',
|
||||
state.entity_id)
|
||||
continue
|
||||
|
||||
if state.domain == 'media_player' and state.attributes and \
|
||||
'media_type' in state.attributes and \
|
||||
'media_id' in state.attributes:
|
||||
service = SERVICE_PLAY_MEDIA
|
||||
elif state.domain == 'media_player' and state.state == STATE_PAUSED:
|
||||
service = SERVICE_MEDIA_PAUSE
|
||||
elif state.domain == 'media_player' and state.state == STATE_PLAYING:
|
||||
service = SERVICE_MEDIA_PLAY
|
||||
elif state.state == STATE_ON:
|
||||
service = SERVICE_TURN_ON
|
||||
elif state.state == STATE_OFF:
|
||||
service = SERVICE_TURN_OFF
|
||||
if state.domain == GROUP_DOMAIN:
|
||||
service_domain = HASS_DOMAIN
|
||||
else:
|
||||
service_domain = state.domain
|
||||
|
||||
domain_services = hass.services.services[service_domain]
|
||||
|
||||
service = None
|
||||
for _service in domain_services.keys():
|
||||
if (_service in SERVICE_ATTRIBUTES and
|
||||
all(attr in state.attributes
|
||||
for attr in SERVICE_ATTRIBUTES[_service]) or
|
||||
_service in SERVICE_TO_STATE and
|
||||
SERVICE_TO_STATE[_service] == state.state):
|
||||
service = _service
|
||||
if (_service in SERVICE_TO_STATE and
|
||||
SERVICE_TO_STATE[_service] == state.state):
|
||||
break
|
||||
|
||||
if not service:
|
||||
_LOGGER.warning("reproduce_state: Unable to reproduce state %s",
|
||||
state)
|
||||
continue
|
||||
|
||||
if state.domain == 'group':
|
||||
service_domain = 'homeassistant'
|
||||
else:
|
||||
service_domain = state.domain
|
||||
|
||||
# We group service calls for entities by service call
|
||||
# json used to create a hashable version of dict with maybe lists in it
|
||||
key = (service_domain, service,
|
||||
@ -96,7 +146,8 @@ def reproduce_state(hass, states, blocking=False):
|
||||
|
||||
|
||||
def state_as_number(state):
|
||||
"""Try to coerce our state to a number.
|
||||
"""
|
||||
Try to coerce our state to a number.
|
||||
|
||||
Raises ValueError if this is not possible.
|
||||
"""
|
||||
|
@ -5,13 +5,15 @@ from unittest.mock import patch
|
||||
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.components as core_components
|
||||
from homeassistant.const import SERVICE_TURN_ON
|
||||
from homeassistant.const import (SERVICE_TURN_ON, SERVICE_TURN_OFF)
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.helpers import state
|
||||
from homeassistant.const import (
|
||||
STATE_OPEN, STATE_CLOSED,
|
||||
STATE_LOCKED, STATE_UNLOCKED,
|
||||
STATE_ON, STATE_OFF)
|
||||
from homeassistant.components.media_player import (
|
||||
SERVICE_PLAY_MEDIA, SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PAUSE)
|
||||
from homeassistant.components.sun import (STATE_ABOVE_HORIZON,
|
||||
STATE_BELOW_HORIZON)
|
||||
|
||||
@ -22,16 +24,16 @@ class TestStateHelpers(unittest.TestCase):
|
||||
"""Test the Home Assistant event helpers."""
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
"""Run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
core_components.setup(self.hass, {})
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
"""Stop down everything that was started."""
|
||||
"""Stop when tests are finished."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_get_changed_since(self):
|
||||
"""Test for changes since."""
|
||||
"""Test get_changed_since."""
|
||||
point1 = dt_util.utcnow()
|
||||
point2 = point1 + timedelta(seconds=5)
|
||||
point3 = point2 + timedelta(seconds=5)
|
||||
@ -77,8 +79,19 @@ class TestStateHelpers(unittest.TestCase):
|
||||
sorted([state2, state3], key=lambda state: state.entity_id),
|
||||
sorted(states, key=lambda state: state.entity_id))
|
||||
|
||||
def test_reproduce_state_with_turn_on(self):
|
||||
"""Test reproduction of state with turn_on."""
|
||||
def test_reproduce_with_no_entity(self):
|
||||
"""Test reproduce_state with no entity."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
state.reproduce_state(self.hass, ha.State('light.test', 'on'))
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(len(calls) == 0)
|
||||
self.assertEqual(None, self.hass.states.get('light.test'))
|
||||
|
||||
def test_reproduce_turn_on(self):
|
||||
"""Test reproduce_state with SERVICE_TURN_ON."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
self.hass.states.set('light.test', 'off')
|
||||
@ -93,8 +106,24 @@ class TestStateHelpers(unittest.TestCase):
|
||||
self.assertEqual(SERVICE_TURN_ON, last_call.service)
|
||||
self.assertEqual(['light.test'], last_call.data.get('entity_id'))
|
||||
|
||||
def test_reproduce_state_with_complex_service_data(self):
|
||||
"""Test reproduction of state with complex service data."""
|
||||
def test_reproduce_turn_off(self):
|
||||
"""Test reproduce_state with SERVICE_TURN_OFF."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_OFF)
|
||||
|
||||
self.hass.states.set('light.test', 'on')
|
||||
|
||||
state.reproduce_state(self.hass, ha.State('light.test', 'off'))
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(len(calls) > 0)
|
||||
last_call = calls[-1]
|
||||
self.assertEqual('light', last_call.domain)
|
||||
self.assertEqual(SERVICE_TURN_OFF, last_call.service)
|
||||
self.assertEqual(['light.test'], last_call.data.get('entity_id'))
|
||||
|
||||
def test_reproduce_complex_data(self):
|
||||
"""Test reproduce_state with complex service data."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
self.hass.states.set('light.test', 'off')
|
||||
@ -113,8 +142,78 @@ class TestStateHelpers(unittest.TestCase):
|
||||
self.assertEqual(SERVICE_TURN_ON, last_call.service)
|
||||
self.assertEqual(complex_data, last_call.data.get('complex'))
|
||||
|
||||
def test_reproduce_state_with_group(self):
|
||||
"""Test reproduction of state with group."""
|
||||
def test_reproduce_media_data(self):
|
||||
"""Test reproduce_state with SERVICE_PLAY_MEDIA."""
|
||||
calls = mock_service(self.hass, 'media_player', SERVICE_PLAY_MEDIA)
|
||||
|
||||
self.hass.states.set('media_player.test', 'off')
|
||||
|
||||
media_attributes = {'media_content_type': 'movie',
|
||||
'media_content_id': 'batman'}
|
||||
|
||||
state.reproduce_state(self.hass, ha.State('media_player.test', 'None',
|
||||
media_attributes))
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(len(calls) > 0)
|
||||
last_call = calls[-1]
|
||||
self.assertEqual('media_player', last_call.domain)
|
||||
self.assertEqual(SERVICE_PLAY_MEDIA, last_call.service)
|
||||
self.assertEqual('movie', last_call.data.get('media_content_type'))
|
||||
self.assertEqual('batman', last_call.data.get('media_content_id'))
|
||||
|
||||
def test_reproduce_media_play(self):
|
||||
"""Test reproduce_state with SERVICE_MEDIA_PLAY."""
|
||||
calls = mock_service(self.hass, 'media_player', SERVICE_MEDIA_PLAY)
|
||||
|
||||
self.hass.states.set('media_player.test', 'off')
|
||||
|
||||
state.reproduce_state(
|
||||
self.hass, ha.State('media_player.test', 'playing'))
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(len(calls) > 0)
|
||||
last_call = calls[-1]
|
||||
self.assertEqual('media_player', last_call.domain)
|
||||
self.assertEqual(SERVICE_MEDIA_PLAY, last_call.service)
|
||||
self.assertEqual(['media_player.test'],
|
||||
last_call.data.get('entity_id'))
|
||||
|
||||
def test_reproduce_media_pause(self):
|
||||
"""Test reproduce_state with SERVICE_MEDIA_PAUSE."""
|
||||
calls = mock_service(self.hass, 'media_player', SERVICE_MEDIA_PAUSE)
|
||||
|
||||
self.hass.states.set('media_player.test', 'playing')
|
||||
|
||||
state.reproduce_state(
|
||||
self.hass, ha.State('media_player.test', 'paused'))
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(len(calls) > 0)
|
||||
last_call = calls[-1]
|
||||
self.assertEqual('media_player', last_call.domain)
|
||||
self.assertEqual(SERVICE_MEDIA_PAUSE, last_call.service)
|
||||
self.assertEqual(['media_player.test'],
|
||||
last_call.data.get('entity_id'))
|
||||
|
||||
def test_reproduce_bad_state(self):
|
||||
"""Test reproduce_state with bad state."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
self.hass.states.set('light.test', 'off')
|
||||
|
||||
state.reproduce_state(self.hass, ha.State('light.test', 'bad'))
|
||||
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertTrue(len(calls) == 0)
|
||||
self.assertEqual('off', self.hass.states.get('light.test').state)
|
||||
|
||||
def test_reproduce_group(self):
|
||||
"""Test reproduce_state with group."""
|
||||
light_calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
self.hass.states.set('group.test', 'off', {
|
||||
@ -131,8 +230,8 @@ class TestStateHelpers(unittest.TestCase):
|
||||
self.assertEqual(['light.test1', 'light.test2'],
|
||||
last_call.data.get('entity_id'))
|
||||
|
||||
def test_reproduce_state_group_states_with_same_domain_and_data(self):
|
||||
"""Test reproduction of state with the dame domain."""
|
||||
def test_reproduce_group_same_data(self):
|
||||
"""Test reproduce_state with group with same domain and data."""
|
||||
light_calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
self.hass.states.set('light.test1', 'off')
|
||||
@ -153,7 +252,7 @@ class TestStateHelpers(unittest.TestCase):
|
||||
self.assertEqual(95, last_call.data.get('brightness'))
|
||||
|
||||
def test_as_number_states(self):
|
||||
"""Test number as states."""
|
||||
"""Test state_as_number with states."""
|
||||
zero_states = (STATE_OFF, STATE_CLOSED, STATE_UNLOCKED,
|
||||
STATE_BELOW_HORIZON)
|
||||
one_states = (STATE_ON, STATE_OPEN, STATE_LOCKED, STATE_ABOVE_HORIZON)
|
||||
@ -165,7 +264,7 @@ class TestStateHelpers(unittest.TestCase):
|
||||
ha.State('domain.test', _state, {})))
|
||||
|
||||
def test_as_number_coercion(self):
|
||||
"""Test numbers."""
|
||||
"""Test state_as_number with number."""
|
||||
for _state in ('0', '0.0', 0, 0.0):
|
||||
self.assertEqual(
|
||||
0.0, state.state_as_number(
|
||||
@ -176,7 +275,7 @@ class TestStateHelpers(unittest.TestCase):
|
||||
ha.State('domain.test', _state, {})))
|
||||
|
||||
def test_as_number_invalid_cases(self):
|
||||
"""."""
|
||||
"""Test state_as_number with invalid cases."""
|
||||
for _state in ('', 'foo', 'foo.bar', None, False, True, object,
|
||||
object()):
|
||||
self.assertRaises(ValueError,
|
||||
|
Loading…
x
Reference in New Issue
Block a user