Add transition support to scenes, cleanup blocking parameter (#34434)

This commit is contained in:
Franck Nijhof 2020-04-21 03:07:50 +02:00 committed by GitHub
parent 19be31d13a
commit bc5a2da7b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 547 additions and 229 deletions

View file

@ -1,7 +1,7 @@
"""Reproduce an Alarm control panel state.""" """Reproduce an Alarm control panel state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -36,7 +36,11 @@ VALID_STATES = {
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -76,9 +80,18 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Alarm control panel states.""" """Reproduce Alarm control panel states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,7 +1,7 @@
"""Reproduce an Automation state.""" """Reproduce an Automation state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -21,7 +21,11 @@ VALID_STATES = {STATE_ON, STATE_OFF}
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -53,9 +57,18 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Automation states.""" """Reproduce Automation states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,6 +1,6 @@
"""Module that groups code required to handle state restore for component.""" """Module that groups code required to handle state restore for component."""
import asyncio import asyncio
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ATTR_TEMPERATURE from homeassistant.const import ATTR_TEMPERATURE
from homeassistant.core import Context, State from homeassistant.core import Context, State
@ -26,7 +26,11 @@ from .const import (
async def _async_reproduce_states( async def _async_reproduce_states(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce component states.""" """Reproduce component states."""
@ -69,9 +73,18 @@ async def _async_reproduce_states(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce component states.""" """Reproduce component states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_states(hass, state, context) for state in states) *(
_async_reproduce_states(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,7 +1,7 @@
"""Reproduce an Counter state.""" """Reproduce an Counter state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import Context, State from homeassistant.core import Context, State
@ -21,7 +21,11 @@ _LOGGER = logging.getLogger(__name__)
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -63,9 +67,18 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Counter states.""" """Reproduce Counter states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,7 +1,7 @@
"""Reproduce an Cover state.""" """Reproduce an Cover state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.components.cover import ( from homeassistant.components.cover import (
ATTR_CURRENT_POSITION, ATTR_CURRENT_POSITION,
@ -33,7 +33,11 @@ VALID_STATES = {STATE_CLOSED, STATE_CLOSING, STATE_OPEN, STATE_OPENING}
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -61,13 +65,15 @@ async def _async_reproduce_state(
service_data = {ATTR_ENTITY_ID: state.entity_id} service_data = {ATTR_ENTITY_ID: state.entity_id}
service_data_tilting = {ATTR_ENTITY_ID: state.entity_id} service_data_tilting = {ATTR_ENTITY_ID: state.entity_id}
if cur_state.state != state.state or cur_state.attributes.get( if not (
ATTR_CURRENT_POSITION cur_state.state == state.state
) != state.attributes.get(ATTR_CURRENT_POSITION): and cur_state.attributes.get(ATTR_CURRENT_POSITION)
== state.attributes.get(ATTR_CURRENT_POSITION)
):
# Open/Close # Open/Close
if state.state == STATE_CLOSED or state.state == STATE_CLOSING: if state.state in [STATE_CLOSED, STATE_CLOSING]:
service = SERVICE_CLOSE_COVER service = SERVICE_CLOSE_COVER
elif state.state == STATE_OPEN or state.state == STATE_OPENING: elif state.state in [STATE_OPEN, STATE_OPENING]:
if ( if (
ATTR_CURRENT_POSITION in cur_state.attributes ATTR_CURRENT_POSITION in cur_state.attributes
and ATTR_CURRENT_POSITION in state.attributes and ATTR_CURRENT_POSITION in state.attributes
@ -108,10 +114,19 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Cover states.""" """Reproduce Cover states."""
# Reproduce states in parallel. # Reproduce states in parallel.
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,4 +1,6 @@
"""Support for deCONZ scenes.""" """Support for deCONZ scenes."""
from typing import Any
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -18,10 +20,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
@callback @callback
def async_add_scene(scenes): def async_add_scene(scenes):
"""Add scene from deCONZ.""" """Add scene from deCONZ."""
entities = [] entities = [DeconzScene(scene, gateway) for scene in scenes]
for scene in scenes:
entities.append(DeconzScene(scene, gateway))
async_add_entities(entities) async_add_entities(entities)
@ -51,7 +50,7 @@ class DeconzScene(Scene):
del self.gateway.deconz_ids[self.entity_id] del self.gateway.deconz_ids[self.entity_id]
self._scene = None self._scene = None
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
await self._scene.async_set_state({}) await self._scene.async_set_state({})

View file

@ -1,4 +1,6 @@
"""Support for control of ElkM1 tasks ("macros").""" """Support for control of ElkM1 tasks ("macros")."""
from typing import Any
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
from . import ElkAttachedEntity, create_elk_entities from . import ElkAttachedEntity, create_elk_entities
@ -17,6 +19,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class ElkTask(ElkAttachedEntity, Scene): class ElkTask(ElkAttachedEntity, Scene):
"""Elk-M1 task as scene.""" """Elk-M1 task as scene."""
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate the task.""" """Activate the task."""
self._element.activate() self._element.activate()

View file

@ -2,7 +2,7 @@
import asyncio import asyncio
import logging import logging
from types import MappingProxyType from types import MappingProxyType
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -35,7 +35,11 @@ ATTRIBUTES = { # attribute: service
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -85,11 +89,20 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Fan states.""" """Reproduce Fan states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,5 +1,6 @@
"""Support for Fibaro scenes.""" """Support for Fibaro scenes."""
import logging import logging
from typing import Any
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
@ -21,6 +22,6 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
class FibaroScene(FibaroDevice, Scene): class FibaroScene(FibaroDevice, Scene):
"""Representation of a Fibaro scene entity.""" """Representation of a Fibaro scene entity."""
def activate(self): def activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
self.fibaro_device.start() self.fibaro_device.start()

View file

@ -1,5 +1,5 @@
"""Module that groups code required to handle state restore for component.""" """Module that groups code required to handle state restore for component."""
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.core import Context, State from homeassistant.core import Context, State
from homeassistant.helpers.state import async_reproduce_state from homeassistant.helpers.state import async_reproduce_state
@ -9,7 +9,11 @@ from . import get_entity_ids
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce component states.""" """Reproduce component states."""
@ -27,4 +31,6 @@ async def async_reproduce_states(
context=state.context, context=state.context,
) )
) )
await async_reproduce_state(hass, states_copy, blocking=True, context=context) await async_reproduce_state(
hass, states_copy, context=context, reproduce_options=reproduce_options
)

View file

@ -1,11 +1,12 @@
"""Allow users to set and activate scenes.""" """Allow users to set and activate scenes."""
from collections import namedtuple from collections import namedtuple
import logging import logging
from typing import List from typing import Any, List
import voluptuous as vol import voluptuous as vol
from homeassistant import config as conf_util from homeassistant import config as conf_util
from homeassistant.components.light import ATTR_TRANSITION
from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN, STATES, Scene from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN, STATES, Scene
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -62,8 +63,8 @@ def _ensure_no_intersection(value):
if ( if (
CONF_SNAPSHOT not in value CONF_SNAPSHOT not in value
or CONF_ENTITIES not in value or CONF_ENTITIES not in value
or not any( or all(
entity_id in value[CONF_SNAPSHOT] for entity_id in value[CONF_ENTITIES] entity_id not in value[CONF_SNAPSHOT] for entity_id in value[CONF_ENTITIES]
) )
): ):
return value return value
@ -123,13 +124,11 @@ def scenes_with_entity(hass: HomeAssistant, entity_id: str) -> List[str]:
platform = hass.data[DATA_PLATFORM] platform = hass.data[DATA_PLATFORM]
results = [] return [
scene_entity.entity_id
for scene_entity in platform.entities.values(): for scene_entity in platform.entities.values()
if entity_id in scene_entity.scene_config.states: if entity_id in scene_entity.scene_config.states
results.append(scene_entity.entity_id) ]
return results
@callback @callback
@ -171,7 +170,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
conf = await conf_util.async_process_component_config(hass, conf, integration) conf = await conf_util.async_process_component_config(hass, conf, integration)
if not conf or not platform: if not (conf and platform):
return return
await platform.async_reset() await platform.async_reset()
@ -189,15 +188,30 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
async def apply_service(call): async def apply_service(call):
"""Apply a scene.""" """Apply a scene."""
reproduce_options = {}
if ATTR_TRANSITION in call.data:
reproduce_options[ATTR_TRANSITION] = call.data.get(ATTR_TRANSITION)
await async_reproduce_state( await async_reproduce_state(
hass, call.data[CONF_ENTITIES].values(), blocking=True, context=call.context hass,
call.data[CONF_ENTITIES].values(),
context=call.context,
reproduce_options=reproduce_options,
) )
hass.services.async_register( hass.services.async_register(
SCENE_DOMAIN, SCENE_DOMAIN,
SERVICE_APPLY, SERVICE_APPLY,
apply_service, apply_service,
vol.Schema({vol.Required(CONF_ENTITIES): STATES_SCHEMA}), vol.Schema(
{
vol.Optional(ATTR_TRANSITION): vol.All(
vol.Coerce(float), vol.Clamp(min=0, max=6553)
),
vol.Required(CONF_ENTITIES): STATES_SCHEMA,
}
),
) )
async def create_service(call): async def create_service(call):
@ -289,11 +303,11 @@ class HomeAssistantScene(Scene):
attributes[CONF_ID] = unique_id attributes[CONF_ID] = unique_id
return attributes return attributes
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate scene. Try to get entities into requested state.""" """Activate scene. Try to get entities into requested state."""
await async_reproduce_state( await async_reproduce_state(
self.hass, self.hass,
self.scene_config.states.values(), self.scene_config.states.values(),
blocking=True,
context=self._context, context=self._context,
reproduce_options=kwargs,
) )

View file

@ -1,5 +1,6 @@
"""Support for Powerview scenes from a Powerview hub.""" """Support for Powerview scenes from a Powerview hub."""
import logging import logging
from typing import Any
from aiopvapi.helpers.aiorequest import AioRequest from aiopvapi.helpers.aiorequest import AioRequest
from aiopvapi.resources.scene import Scene as PvScene from aiopvapi.resources.scene import Scene as PvScene
@ -97,6 +98,6 @@ class PowerViewScene(Scene):
"""Icon to use in the frontend.""" """Icon to use in the frontend."""
return "mdi:blinds" return "mdi:blinds"
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate scene. Try to get entities into requested state.""" """Activate scene. Try to get entities into requested state."""
await self._scene.activate() await self._scene.activate()

View file

@ -1,7 +1,7 @@
"""Reproduce an input boolean state.""" """Reproduce an input boolean state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -19,7 +19,11 @@ _LOGGER = logging.getLogger(__name__)
async def _async_reproduce_states( async def _async_reproduce_states(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce input boolean states.""" """Reproduce input boolean states."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -49,9 +53,18 @@ async def _async_reproduce_states(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce component states.""" """Reproduce component states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_states(hass, state, context) for state in states) *(
_async_reproduce_states(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,7 +1,7 @@
"""Reproduce an Input datetime state.""" """Reproduce an Input datetime state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import Context, State from homeassistant.core import Context, State
@ -40,7 +40,11 @@ def is_valid_time(string: str) -> bool:
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -97,9 +101,18 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Input datetime states.""" """Reproduce Input datetime states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,7 +1,7 @@
"""Reproduce an Input number state.""" """Reproduce an Input number state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
import voluptuous as vol import voluptuous as vol
@ -15,7 +15,11 @@ _LOGGER = logging.getLogger(__name__)
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -49,10 +53,19 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Input number states.""" """Reproduce Input number states."""
# Reproduce states in parallel. # Reproduce states in parallel.
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -2,7 +2,7 @@
import asyncio import asyncio
import logging import logging
from types import MappingProxyType from types import MappingProxyType
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import Context, State from homeassistant.core import Context, State
@ -22,7 +22,11 @@ _LOGGER = logging.getLogger(__name__)
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -64,12 +68,21 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Input select states.""" """Reproduce Input select states."""
# Reproduce states in parallel. # Reproduce states in parallel.
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,7 +1,7 @@
"""Reproduce an Input text state.""" """Reproduce an Input text state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import Context, State from homeassistant.core import Context, State
@ -13,7 +13,11 @@ _LOGGER = logging.getLogger(__name__)
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -37,10 +41,19 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Input text states.""" """Reproduce Input text states."""
# Reproduce states in parallel. # Reproduce states in parallel.
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,4 +1,6 @@
"""Support for KNX scenes.""" """Support for KNX scenes."""
from typing import Any
import voluptuous as vol import voluptuous as vol
from xknx.devices import Scene as XknxScene from xknx.devices import Scene as XknxScene
@ -65,6 +67,6 @@ class KNXScene(Scene):
"""Return the name of the scene.""" """Return the name of the scene."""
return self.scene.name return self.scene.name
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
await self.scene.run() await self.scene.run()

View file

@ -1,4 +1,6 @@
"""Support for LCN scenes.""" """Support for LCN scenes."""
from typing import Any
import pypck import pypck
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
@ -63,7 +65,7 @@ class LcnScene(LcnDevice, Scene):
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Run when entity about to be added to hass.""" """Run when entity about to be added to hass."""
async def async_activate(self): def activate(self, **kwargs: Any) -> None:
"""Activate scene.""" """Activate scene."""
self.address_connection.activate_scene( self.address_connection.activate_scene(
self.register_id, self.register_id,

View file

@ -1,6 +1,7 @@
"""Support for LIFX Cloud scenes.""" """Support for LIFX Cloud scenes."""
import asyncio import asyncio
import logging import logging
from typing import Any
import aiohttp import aiohttp
from aiohttp.hdrs import AUTHORIZATION from aiohttp.hdrs import AUTHORIZATION
@ -46,9 +47,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
status = scenes_resp.status status = scenes_resp.status
if status == HTTP_OK: if status == HTTP_OK:
data = await scenes_resp.json() data = await scenes_resp.json()
devices = [] devices = [LifxCloudScene(hass, headers, timeout, scene) for scene in data]
for scene in data:
devices.append(LifxCloudScene(hass, headers, timeout, scene))
async_add_entities(devices) async_add_entities(devices)
return True return True
if status == 401: if status == 401:
@ -75,7 +74,7 @@ class LifxCloudScene(Scene):
"""Return the name of the scene.""" """Return the name of the scene."""
return self._name return self._name
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
url = f"https://api.lifx.com/v1/scenes/scene_id:{self._uuid}/activate" url = f"https://api.lifx.com/v1/scenes/scene_id:{self._uuid}/activate"

View file

@ -40,7 +40,7 @@ SUPPORT_COLOR = 16
SUPPORT_TRANSITION = 32 SUPPORT_TRANSITION = 32
SUPPORT_WHITE_VALUE = 128 SUPPORT_WHITE_VALUE = 128
# Integer that represents transition time in seconds to make change. # Float that represents transition time in seconds to make change.
ATTR_TRANSITION = "transition" ATTR_TRANSITION = "transition"
# Lists holding color values # Lists holding color values

View file

@ -2,7 +2,7 @@
import asyncio import asyncio
import logging import logging
from types import MappingProxyType from types import MappingProxyType
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -71,7 +71,11 @@ DEPRECATION_WARNING = (
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -98,7 +102,10 @@ async def _async_reproduce_state(
): ):
return return
service_data = {ATTR_ENTITY_ID: state.entity_id} service_data: Dict[str, Any] = {ATTR_ENTITY_ID: state.entity_id}
if reproduce_options is not None and ATTR_TRANSITION in reproduce_options:
service_data[ATTR_TRANSITION] = reproduce_options[ATTR_TRANSITION]
if state.state == STATE_ON: if state.state == STATE_ON:
service = SERVICE_TURN_ON service = SERVICE_TURN_ON
@ -122,11 +129,20 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Light states.""" """Reproduce Light states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,5 +1,6 @@
"""Support for LiteJet scenes.""" """Support for LiteJet scenes."""
import logging import logging
from typing import Any
from homeassistant.components import litejet from homeassistant.components import litejet
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
@ -40,6 +41,6 @@ class LiteJetScene(Scene):
"""Return the device-specific state attributes.""" """Return the device-specific state attributes."""
return {ATTR_NUMBER: self._index} return {ATTR_NUMBER: self._index}
def activate(self): def activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
self._lj.activate_scene(self._index) self._lj.activate_scene(self._index)

View file

@ -1,7 +1,7 @@
"""Reproduce an Lock state.""" """Reproduce an Lock state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -21,7 +21,11 @@ VALID_STATES = {STATE_LOCKED, STATE_UNLOCKED}
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -53,9 +57,18 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Lock states.""" """Reproduce Lock states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,5 +1,6 @@
"""Support for Lutron scenes.""" """Support for Lutron scenes."""
import logging import logging
from typing import Any
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
@ -30,7 +31,7 @@ class LutronScene(LutronDevice, Scene):
self._keypad_name = keypad_name self._keypad_name = keypad_name
self._led = lutron_led self._led = lutron_led
def activate(self): def activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
self._lutron_device.press() self._lutron_device.press()

View file

@ -1,5 +1,6 @@
"""Support for Lutron Caseta scenes.""" """Support for Lutron Caseta scenes."""
import logging import logging
from typing import Any
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
@ -34,6 +35,6 @@ class LutronCasetaScene(Scene):
"""Return the name of the scene.""" """Return the name of the scene."""
return self._scene_name return self._scene_name
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
self._bridge.activate_scene(self._scene_id) self._bridge.activate_scene(self._scene_id)

View file

@ -1,6 +1,6 @@
"""Module that groups code required to handle state restore for component.""" """Module that groups code required to handle state restore for component."""
import asyncio import asyncio
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PAUSE,
@ -39,14 +39,17 @@ from .const import (
async def _async_reproduce_states( async def _async_reproduce_states(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce component states.""" """Reproduce component states."""
async def call_service(service: str, keys: Iterable) -> None: async def call_service(service: str, keys: Iterable) -> None:
"""Call service with set of attributes given.""" """Call service with set of attributes given."""
data = {} data = {"entity_id": state.entity_id}
data["entity_id"] = state.entity_id
for key in keys: for key in keys:
if key in state.attributes: if key in state.attributes:
data[key] = state.attributes[key] data[key] = state.attributes[key]
@ -91,9 +94,18 @@ async def _async_reproduce_states(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce component states.""" """Reproduce component states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_states(hass, state, context) for state in states) *(
_async_reproduce_states(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,5 +1,7 @@
"""Support for Nexia Automations.""" """Support for Nexia Automations."""
from typing import Any
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
from homeassistant.helpers.event import async_call_later from homeassistant.helpers.event import async_call_later
@ -48,7 +50,7 @@ class NexiaAutomationScene(NexiaEntity, Scene):
"""Return the icon of the automation scene.""" """Return the icon of the automation scene."""
return "mdi:script-text-outline" return "mdi:script-text-outline"
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate an automation scene.""" """Activate an automation scene."""
await self.hass.async_add_executor_job(self._automation.activate) await self.hass.async_add_executor_job(self._automation.activate)

View file

@ -1,7 +1,7 @@
"""Reproduce an Remote state.""" """Reproduce an Remote state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -21,7 +21,11 @@ VALID_STATES = {STATE_ON, STATE_OFF}
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -53,9 +57,18 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Remote states.""" """Reproduce Remote states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,9 +1,12 @@
"""Allow users to set and activate scenes.""" """Allow users to set and activate scenes."""
import functools as ft
import importlib import importlib
import logging import logging
from typing import Any, Optional
import voluptuous as vol import voluptuous as vol
from homeassistant.components.light import ATTR_TRANSITION
from homeassistant.const import CONF_PLATFORM, SERVICE_TURN_ON from homeassistant.const import CONF_PLATFORM, SERVICE_TURN_ON
from homeassistant.core import DOMAIN as HA_DOMAIN from homeassistant.core import DOMAIN as HA_DOMAIN
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
@ -62,7 +65,11 @@ async def async_setup(hass, config):
await component.async_setup(config) await component.async_setup(config)
# Ensure Home Assistant platform always loaded. # Ensure Home Assistant platform always loaded.
await component.async_setup_platform(HA_DOMAIN, {"platform": HA_DOMAIN, STATES: []}) await component.async_setup_platform(HA_DOMAIN, {"platform": HA_DOMAIN, STATES: []})
component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_activate") component.async_register_entity_service(
SERVICE_TURN_ON,
{ATTR_TRANSITION: vol.All(vol.Coerce(float), vol.Clamp(min=0, max=6553))},
"async_activate",
)
return True return True
@ -81,19 +88,22 @@ class Scene(Entity):
"""A scene is a group of entities and the states we want them to be.""" """A scene is a group of entities and the states we want them to be."""
@property @property
def should_poll(self): def should_poll(self) -> bool:
"""No polling needed.""" """No polling needed."""
return False return False
@property @property
def state(self): def state(self) -> Optional[str]:
"""Return the state of the scene.""" """Return the state of the scene."""
return STATE return STATE
def activate(self): def activate(self, **kwargs: Any) -> None:
"""Activate scene. Try to get entities into requested state.""" """Activate scene. Try to get entities into requested state."""
raise NotImplementedError() raise NotImplementedError()
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate scene. Try to get entities into requested state.""" """Activate scene. Try to get entities into requested state."""
await self.hass.async_add_job(self.activate) assert self.hass
task = self.hass.async_add_job(ft.partial(self.activate, **kwargs))
if task:
await task

View file

@ -3,6 +3,11 @@
turn_on: turn_on:
description: Activate a scene. description: Activate a scene.
fields: fields:
transition:
description:
Transition duration in seconds it takes to bring devices to the state
defined in the scene.
example: 2.5
entity_id: entity_id:
description: Name(s) of scenes to turn on description: Name(s) of scenes to turn on
example: "scene.romantic" example: "scene.romantic"
@ -11,8 +16,15 @@ reload:
description: Reload the scene configuration description: Reload the scene configuration
apply: apply:
description: Activate a scene. Takes same data as the entities field from a single scene in the config. description:
Activate a scene. Takes same data as the entities field from a single scene
in the config.
fields: fields:
transition:
description:
Transition duration in seconds it takes to bring devices to the state
defined in the scene.
example: 2.5
entities: entities:
description: The entities and the state that they need to be. description: The entities and the state that they need to be.
example: example:

View file

@ -1,4 +1,6 @@
"""Support for scenes through the SmartThings cloud API.""" """Support for scenes through the SmartThings cloud API."""
from typing import Any
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
from .const import DATA_BROKERS, DOMAIN from .const import DATA_BROKERS, DOMAIN
@ -17,7 +19,7 @@ class SmartThingsScene(Scene):
"""Init the scene class.""" """Init the scene class."""
self._scene = scene self._scene = scene
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate scene.""" """Activate scene."""
await self._scene.execute() await self._scene.execute()

View file

@ -1,7 +1,7 @@
"""Reproduce an Switch state.""" """Reproduce an Switch state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -21,7 +21,11 @@ VALID_STATES = {STATE_ON, STATE_OFF}
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -53,9 +57,18 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Switch states.""" """Reproduce Switch states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,5 +1,6 @@
"""Support for Tahoma scenes.""" """Support for Tahoma scenes."""
import logging import logging
from typing import Any
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
@ -13,9 +14,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
if discovery_info is None: if discovery_info is None:
return return
controller = hass.data[TAHOMA_DOMAIN]["controller"] controller = hass.data[TAHOMA_DOMAIN]["controller"]
scenes = [] scenes = [
for scene in hass.data[TAHOMA_DOMAIN]["scenes"]: TahomaScene(scene, controller) for scene in hass.data[TAHOMA_DOMAIN]["scenes"]
scenes.append(TahomaScene(scene, controller)) ]
add_entities(scenes, True) add_entities(scenes, True)
@ -28,7 +30,7 @@ class TahomaScene(Scene):
self.controller = controller self.controller = controller
self._name = self.tahoma_scene.name self._name = self.tahoma_scene.name
def activate(self): def activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
self.controller.launch_action_group(self.tahoma_scene.oid) self.controller.launch_action_group(self.tahoma_scene.oid)

View file

@ -1,7 +1,7 @@
"""Reproduce an Timer state.""" """Reproduce an Timer state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import Context, State from homeassistant.core import Context, State
@ -24,7 +24,11 @@ VALID_STATES = {STATUS_IDLE, STATUS_ACTIVE, STATUS_PAUSED}
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -62,9 +66,18 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Timer states.""" """Reproduce Timer states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,4 +1,6 @@
"""Support for the Tuya scenes.""" """Support for the Tuya scenes."""
from typing import Any
from homeassistant.components.scene import DOMAIN, Scene from homeassistant.components.scene import DOMAIN, Scene
from . import DATA_TUYA, TuyaDevice from . import DATA_TUYA, TuyaDevice
@ -29,6 +31,6 @@ class TuyaScene(TuyaDevice, Scene):
super().__init__(tuya) super().__init__(tuya)
self.entity_id = ENTITY_ID_FORMAT.format(tuya.object_id()) self.entity_id = ENTITY_ID_FORMAT.format(tuya.object_id())
def activate(self): def activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
self.tuya.activate() self.tuya.activate()

View file

@ -1,7 +1,7 @@
"""Reproduce an Vacuum state.""" """Reproduce an Vacuum state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -41,7 +41,11 @@ VALID_STATES_STATE = {
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -50,7 +54,7 @@ async def _async_reproduce_state(
_LOGGER.warning("Unable to find entity %s", state.entity_id) _LOGGER.warning("Unable to find entity %s", state.entity_id)
return return
if state.state not in VALID_STATES_TOGGLE and state.state not in VALID_STATES_STATE: if not (state.state in VALID_STATES_TOGGLE or state.state in VALID_STATES_STATE):
_LOGGER.warning( _LOGGER.warning(
"Invalid state specified for %s: %s", state.entity_id, state.state "Invalid state specified for %s: %s", state.entity_id, state.state
) )
@ -72,7 +76,7 @@ async def _async_reproduce_state(
service = SERVICE_TURN_OFF service = SERVICE_TURN_OFF
elif state.state == STATE_CLEANING: elif state.state == STATE_CLEANING:
service = SERVICE_START service = SERVICE_START
elif state.state == STATE_DOCKED or state.state == STATE_RETURNING: elif state.state in [STATE_DOCKED, STATE_RETURNING]:
service = SERVICE_RETURN_TO_BASE service = SERVICE_RETURN_TO_BASE
elif state.state == STATE_IDLE: elif state.state == STATE_IDLE:
service = SERVICE_STOP service = SERVICE_STOP
@ -92,10 +96,19 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Vacuum states.""" """Reproduce Vacuum states."""
# Reproduce states in parallel. # Reproduce states in parallel.
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,4 +1,6 @@
"""Support for VELUX scenes.""" """Support for VELUX scenes."""
from typing import Any
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
from . import _LOGGER, DATA_VELUX from . import _LOGGER, DATA_VELUX
@ -6,9 +8,7 @@ from . import _LOGGER, DATA_VELUX
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the scenes for Velux platform.""" """Set up the scenes for Velux platform."""
entities = [] entities = [VeluxScene(scene) for scene in hass.data[DATA_VELUX].pyvlx.scenes]
for scene in hass.data[DATA_VELUX].pyvlx.scenes:
entities.append(VeluxScene(scene))
async_add_entities(entities) async_add_entities(entities)
@ -25,6 +25,6 @@ class VeluxScene(Scene):
"""Return the name of the scene.""" """Return the name of the scene."""
return self.scene.name return self.scene.name
async def async_activate(self): async def async_activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
await self.scene.run(wait_for_completion=False) await self.scene.run(wait_for_completion=False)

View file

@ -1,6 +1,6 @@
"""Support for Vera scenes.""" """Support for Vera scenes."""
import logging import logging
from typing import Callable, List from typing import Any, Callable, List
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -46,7 +46,7 @@ class VeraScene(Scene):
"""Update the scene status.""" """Update the scene status."""
self.vera_scene.refresh() self.vera_scene.refresh()
def activate(self): def activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
self.vera_scene.activate() self.vera_scene.activate()

View file

@ -1,7 +1,7 @@
"""Reproduce an Water heater state.""" """Reproduce an Water heater state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -44,7 +44,11 @@ VALID_STATES = {
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -117,9 +121,18 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce Water heater states.""" """Reproduce Water heater states."""
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )

View file

@ -1,5 +1,6 @@
"""Support for Wink scenes.""" """Support for Wink scenes."""
import logging import logging
from typing import Any
import pywink import pywink
@ -31,6 +32,6 @@ class WinkScene(WinkDevice, Scene):
"""Call when entity is added to hass.""" """Call when entity is added to hass."""
self.hass.data[DOMAIN]["entities"]["scene"].append(self) self.hass.data[DOMAIN]["entities"]["scene"].append(self)
def activate(self): def activate(self, **kwargs: Any) -> None:
"""Activate the scene.""" """Activate the scene."""
self.wink.activate() self.wink.activate()

View file

@ -4,7 +4,7 @@ from collections import defaultdict
import datetime as dt import datetime as dt
import logging import logging
from types import ModuleType, TracebackType from types import ModuleType, TracebackType
from typing import Dict, Iterable, List, Optional, Type, Union from typing import Any, Dict, Iterable, List, Optional, Type, Union
from homeassistant.components.sun import STATE_ABOVE_HORIZON, STATE_BELOW_HORIZON from homeassistant.components.sun import STATE_ABOVE_HORIZON, STATE_BELOW_HORIZON
from homeassistant.const import ( from homeassistant.const import (
@ -69,8 +69,9 @@ def get_changed_since(
async def async_reproduce_state( async def async_reproduce_state(
hass: HomeAssistantType, hass: HomeAssistantType,
states: Union[State, Iterable[State]], states: Union[State, Iterable[State]],
blocking: bool = False, *,
context: Optional[Context] = None, context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a list of states on multiple domains.""" """Reproduce a list of states on multiple domains."""
if isinstance(states, State): if isinstance(states, State):
@ -97,7 +98,7 @@ async def async_reproduce_state(
return return
await platform.async_reproduce_states( # type: ignore await platform.async_reproduce_states( # type: ignore
hass, states_by_domain, context=context hass, states_by_domain, context=context, reproduce_options=reproduce_options
) )
if to_call: if to_call:

View file

@ -1,7 +1,7 @@
"""Reproduce an NEW_NAME state.""" """Reproduce an NEW_NAME state."""
import asyncio import asyncio
import logging import logging
from typing import Iterable, Optional from typing import Any, Dict, Iterable, Optional
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -22,7 +22,11 @@ VALID_STATES = {STATE_ON, STATE_OFF}
async def _async_reproduce_state( async def _async_reproduce_state(
hass: HomeAssistantType, state: State, context: Optional[Context] = None hass: HomeAssistantType,
state: State,
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -63,16 +67,25 @@ async def _async_reproduce_state(
async def async_reproduce_states( async def async_reproduce_states(
hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None hass: HomeAssistantType,
states: Iterable[State],
*,
context: Optional[Context] = None,
reproduce_options: Optional[Dict[str, Any]] = None,
) -> None: ) -> None:
"""Reproduce NEW_NAME states.""" """Reproduce NEW_NAME states."""
# TODO pick one and remove other one # TODO pick one and remove other one
# Reproduce states in parallel. # Reproduce states in parallel.
await asyncio.gather( await asyncio.gather(
*(_async_reproduce_state(hass, state, context) for state in states) *(
_async_reproduce_state(
hass, state, context=context, reproduce_options=reproduce_options
)
for state in states
)
) )
# Alternative: Reproduce states in sequence # Alternative: Reproduce states in sequence
# for state in states: # for state in states:
# await _async_reproduce_state(hass, state, context) # await _async_reproduce_state(hass, state, context=context, reproduce_options=reproduce_options)

View file

@ -70,8 +70,7 @@ async def test_reproducing_states(hass, caplog):
State("alarm_control_panel.entity_armed_night", STATE_ALARM_ARMED_NIGHT), State("alarm_control_panel.entity_armed_night", STATE_ALARM_ARMED_NIGHT),
State("alarm_control_panel.entity_disarmed", STATE_ALARM_DISARMED), State("alarm_control_panel.entity_disarmed", STATE_ALARM_DISARMED),
State("alarm_control_panel.entity_triggered", STATE_ALARM_TRIGGERED), State("alarm_control_panel.entity_triggered", STATE_ALARM_TRIGGERED),
], ]
blocking=True,
) )
assert len(arm_away_calls) == 0 assert len(arm_away_calls) == 0
@ -83,7 +82,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("alarm_control_panel.entity_triggered", "not_supported")], blocking=True [State("alarm_control_panel.entity_triggered", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -109,8 +108,7 @@ async def test_reproducing_states(hass, caplog):
State("alarm_control_panel.entity_triggered", STATE_ALARM_DISARMED), State("alarm_control_panel.entity_triggered", STATE_ALARM_DISARMED),
# Should not raise # Should not raise
State("alarm_control_panel.non_existing", "on"), State("alarm_control_panel.non_existing", "on"),
], ]
blocking=True,
) )
assert len(arm_away_calls) == 1 assert len(arm_away_calls) == 1

View file

@ -14,8 +14,7 @@ async def test_reproducing_states(hass, caplog):
# These calls should do nothing as entities already in desired state # These calls should do nothing as entities already in desired state
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("automation.entity_off", "off"), State("automation.entity_on", "on")], [State("automation.entity_off", "off"), State("automation.entity_on", "on")]
blocking=True,
) )
assert len(turn_on_calls) == 0 assert len(turn_on_calls) == 0
@ -23,7 +22,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("automation.entity_off", "not_supported")], blocking=True [State("automation.entity_off", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -37,8 +36,7 @@ async def test_reproducing_states(hass, caplog):
State("automation.entity_off", "on"), State("automation.entity_off", "on"),
# Should not raise # Should not raise
State("automation.non_existing", "on"), State("automation.non_existing", "on"),
], ]
blocking=True,
) )
assert len(turn_on_calls) == 1 assert len(turn_on_calls) == 1

View file

@ -82,7 +82,9 @@ async def test_state_with_context(hass):
context = Context() context = Context()
await async_reproduce_states(hass, [State(ENTITY_1, HVAC_MODE_HEAT)], context) await async_reproduce_states(
hass, [State(ENTITY_1, HVAC_MODE_HEAT)], context=context
)
await hass.async_block_till_done() await hass.async_block_till_done()

View file

@ -24,15 +24,14 @@ async def test_reproducing_states(hass, caplog):
"8", "8",
{"initial": 12, "minimum": 5, "maximum": 15, "step": 3}, {"initial": 12, "minimum": 5, "maximum": 15, "step": 3},
), ),
], ]
blocking=True,
) )
assert len(configure_calls) == 0 assert len(configure_calls) == 0
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("counter.entity", "not_supported")], blocking=True [State("counter.entity", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -49,8 +48,7 @@ async def test_reproducing_states(hass, caplog):
), ),
# Should not raise # Should not raise
State("counter.non_existing", "6"), State("counter.non_existing", "6"),
], ]
blocking=True,
) )
valid_calls = [ valid_calls = [

View file

@ -93,8 +93,7 @@ async def test_reproducing_states(hass, caplog):
STATE_OPEN, STATE_OPEN,
{ATTR_CURRENT_POSITION: 100, ATTR_CURRENT_TILT_POSITION: 100}, {ATTR_CURRENT_POSITION: 100, ATTR_CURRENT_TILT_POSITION: 100},
), ),
], ]
blocking=True,
) )
assert len(close_calls) == 0 assert len(close_calls) == 0
@ -106,7 +105,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("cover.entity_close", "not_supported")], blocking=True [State("cover.entity_close", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -145,7 +144,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("cover.non_existing", "on"), State("cover.non_existing", "on"),
], ],
blocking=True,
) )
valid_close_calls = [ valid_close_calls = [

View file

@ -27,7 +27,6 @@ async def test_reproducing_states(hass, caplog):
State("fan.entity_oscillating", "on", {"oscillating": True}), State("fan.entity_oscillating", "on", {"oscillating": True}),
State("fan.entity_direction", "on", {"direction": "forward"}), State("fan.entity_direction", "on", {"direction": "forward"}),
], ],
blocking=True,
) )
assert len(turn_on_calls) == 0 assert len(turn_on_calls) == 0
@ -38,7 +37,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("fan.entity_off", "not_supported")], blocking=True [State("fan.entity_off", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -59,7 +58,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("fan.non_existing", "on"), State("fan.non_existing", "on"),
], ],
blocking=True,
) )
assert len(turn_on_calls) == 1 assert len(turn_on_calls) == 1

View file

@ -39,7 +39,7 @@ async def test_reproduce_group(hass):
state = State("group.test", "on") state = State("group.test", "on")
await async_reproduce_states(hass, [state], context) await async_reproduce_states(hass, [state], context=context)
fun.assert_called_once_with( fun.assert_called_once_with(
hass, hass,
@ -48,6 +48,6 @@ async def test_reproduce_group(hass):
clone_state(state, "light.test2"), clone_state(state, "light.test2"),
clone_state(state, "switch.test1"), clone_state(state, "switch.test1"),
], ],
blocking=True,
context=context, context=context,
reproduce_options=None,
) )

View file

@ -58,6 +58,24 @@ async def test_apply_service(hass):
assert state.state == "on" assert state.state == "on"
assert state.attributes["brightness"] == 50 assert state.attributes["brightness"] == 50
turn_on_calls = async_mock_service(hass, "light", "turn_on")
assert await hass.services.async_call(
"scene",
"apply",
{
"transition": 42,
"entities": {"light.bed_light": {"state": "on", "brightness": 50}},
},
blocking=True,
)
assert len(turn_on_calls) == 1
assert turn_on_calls[0].domain == "light"
assert turn_on_calls[0].service == "turn_on"
assert turn_on_calls[0].data.get("transition") == 42
assert turn_on_calls[0].data.get("entity_id") == "light.bed_light"
assert turn_on_calls[0].data.get("brightness") == 50
async def test_create_service(hass, caplog): async def test_create_service(hass, caplog):
"""Test the create service.""" """Test the create service."""

View file

@ -22,7 +22,6 @@ async def test_reproducing_states(hass):
# Should not raise # Should not raise
State("input_boolean.non_existing", "on"), State("input_boolean.non_existing", "on"),
], ],
blocking=True,
) )
assert hass.states.get("input_boolean.initial_off").state == "on" assert hass.states.get("input_boolean.initial_off").state == "on"
assert hass.states.get("input_boolean.initial_on").state == "off" assert hass.states.get("input_boolean.initial_on").state == "off"
@ -34,7 +33,6 @@ async def test_reproducing_states(hass):
# Set to state it already is. # Set to state it already is.
State("input_boolean.initial_off", "on"), State("input_boolean.initial_off", "on"),
], ],
blocking=True,
) )
assert hass.states.get("input_boolean.initial_on").state == "off" assert hass.states.get("input_boolean.initial_on").state == "off"

View file

@ -29,7 +29,6 @@ async def test_reproducing_states(hass, caplog):
State("input_datetime.entity_time", "01:20:00"), State("input_datetime.entity_time", "01:20:00"),
State("input_datetime.entity_date", "2010-10-10"), State("input_datetime.entity_date", "2010-10-10"),
], ],
blocking=True,
) )
assert len(datetime_calls) == 0 assert len(datetime_calls) == 0
@ -42,7 +41,6 @@ async def test_reproducing_states(hass, caplog):
State("input_datetime.entity_datetime", "not:valid:time"), State("input_datetime.entity_datetime", "not:valid:time"),
State("input_datetime.entity_datetime", "1234-56-78 90:12:34"), State("input_datetime.entity_datetime", "1234-56-78 90:12:34"),
], ],
blocking=True,
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -60,7 +58,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("input_datetime.non_existing", "2010-10-10 01:20:00"), State("input_datetime.non_existing", "2010-10-10 01:20:00"),
], ],
blocking=True,
) )
valid_calls = [ valid_calls = [

View file

@ -26,7 +26,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("input_number.non_existing", "234"), State("input_number.non_existing", "234"),
], ],
blocking=True,
) )
assert hass.states.get("input_number.test_number").state == VALID_NUMBER1 assert hass.states.get("input_number.test_number").state == VALID_NUMBER1
@ -38,14 +37,13 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("input_number.non_existing", "234"), State("input_number.non_existing", "234"),
], ],
blocking=True,
) )
assert hass.states.get("input_number.test_number").state == VALID_NUMBER2 assert hass.states.get("input_number.test_number").state == VALID_NUMBER2
# Test setting state to number out of range # Test setting state to number out of range
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("input_number.test_number", "150")], blocking=True [State("input_number.test_number", "150")]
) )
# The entity states should be unchanged after trying to set them to out-of-range number # The entity states should be unchanged after trying to set them to out-of-range number
@ -58,5 +56,4 @@ async def test_reproducing_states(hass, caplog):
# Set to state it already is. # Set to state it already is.
State("input_number.test_number", VALID_NUMBER2), State("input_number.test_number", VALID_NUMBER2),
], ],
blocking=True,
) )

View file

@ -35,7 +35,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("input_select.non_existing", VALID_OPTION1), State("input_select.non_existing", VALID_OPTION1),
], ],
blocking=True,
) )
# Test that entity is in desired state # Test that entity is in desired state
@ -48,23 +47,20 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("input_select.non_existing", VALID_OPTION3), State("input_select.non_existing", VALID_OPTION3),
], ],
blocking=True,
) )
# Test that we got the desired result # Test that we got the desired result
assert hass.states.get(ENTITY).state == VALID_OPTION3 assert hass.states.get(ENTITY).state == VALID_OPTION3
# Test setting state to invalid state # Test setting state to invalid state
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state([State(ENTITY, INVALID_OPTION)])
[State(ENTITY, INVALID_OPTION)], blocking=True
)
# The entity state should be unchanged # The entity state should be unchanged
assert hass.states.get(ENTITY).state == VALID_OPTION3 assert hass.states.get(ENTITY).state == VALID_OPTION3
# Test setting a different option set # Test setting a different option set
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State(ENTITY, VALID_OPTION5, {"options": VALID_OPTION_SET2})], blocking=True [State(ENTITY, VALID_OPTION5, {"options": VALID_OPTION_SET2})]
) )
# These should fail if options weren't changed to VALID_OPTION_SET2 # These should fail if options weren't changed to VALID_OPTION_SET2

View file

@ -29,7 +29,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("input_text.non_existing", VALID_TEXT1), State("input_text.non_existing", VALID_TEXT1),
], ],
blocking=True,
) )
# Test that entity is in desired state # Test that entity is in desired state
@ -42,7 +41,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("input_text.non_existing", VALID_TEXT2), State("input_text.non_existing", VALID_TEXT2),
], ],
blocking=True,
) )
# Test that the state was changed # Test that the state was changed
@ -50,7 +48,7 @@ async def test_reproducing_states(hass, caplog):
# Test setting state to invalid state (length too long) # Test setting state to invalid state (length too long)
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("input_text.test_text", INVALID_TEXT1)], blocking=True [State("input_text.test_text", INVALID_TEXT1)]
) )
# The entity state should be unchanged # The entity state should be unchanged
@ -58,7 +56,7 @@ async def test_reproducing_states(hass, caplog):
# Test setting state to invalid state (length too short) # Test setting state to invalid state (length too short)
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("input_text.test_text", INVALID_TEXT2)], blocking=True [State("input_text.test_text", INVALID_TEXT2)]
) )
# The entity state should be unchanged # The entity state should be unchanged

View file

@ -53,8 +53,7 @@ async def test_reproducing_states(hass, caplog):
State("light.entity_profile", "on", VALID_PROFILE), State("light.entity_profile", "on", VALID_PROFILE),
State("light.entity_rgb", "on", VALID_RGB_COLOR), State("light.entity_rgb", "on", VALID_RGB_COLOR),
State("light.entity_xy", "on", VALID_XY_COLOR), State("light.entity_xy", "on", VALID_XY_COLOR),
], ]
blocking=True,
) )
assert len(turn_on_calls) == 0 assert len(turn_on_calls) == 0
@ -62,7 +61,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("light.entity_off", "not_supported")], blocking=True [State("light.entity_off", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -86,7 +85,6 @@ async def test_reproducing_states(hass, caplog):
State("light.entity_profile", "on", VALID_RGB_COLOR), State("light.entity_profile", "on", VALID_RGB_COLOR),
State("light.entity_rgb", "on", VALID_XY_COLOR), State("light.entity_rgb", "on", VALID_XY_COLOR),
], ],
blocking=True,
) )
assert len(turn_on_calls) == 12 assert len(turn_on_calls) == 12
@ -163,7 +161,7 @@ async def test_deprecation_warning(hass, caplog):
hass.states.async_set("light.entity_off", "off", {}) hass.states.async_set("light.entity_off", "off", {})
turn_on_calls = async_mock_service(hass, "light", "turn_on") turn_on_calls = async_mock_service(hass, "light", "turn_on")
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("light.entity_off", "on", {"brightness_pct": 80})], blocking=True [State("light.entity_off", "on", {"brightness_pct": 80})]
) )
assert len(turn_on_calls) == 1 assert len(turn_on_calls) == 1
assert DEPRECATION_WARNING % ["brightness_pct"] in caplog.text assert DEPRECATION_WARNING % ["brightness_pct"] in caplog.text

View file

@ -18,7 +18,6 @@ async def test_reproducing_states(hass, caplog):
State("lock.entity_locked", "locked"), State("lock.entity_locked", "locked"),
State("lock.entity_unlocked", "unlocked", {}), State("lock.entity_unlocked", "unlocked", {}),
], ],
blocking=True,
) )
assert len(lock_calls) == 0 assert len(lock_calls) == 0
@ -26,7 +25,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("lock.entity_locked", "not_supported")], blocking=True [State("lock.entity_locked", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -41,7 +40,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("lock.non_existing", "on"), State("lock.non_existing", "on"),
], ],
blocking=True,
) )
assert len(lock_calls) == 1 assert len(lock_calls) == 1

View file

@ -115,7 +115,7 @@ async def test_state_with_context(hass):
context = Context() context = Context()
await async_reproduce_states(hass, [State(ENTITY_1, "on")], context) await async_reproduce_states(hass, [State(ENTITY_1, "on")], context=context)
await hass.async_block_till_done() await hass.async_block_till_done()

View file

@ -15,7 +15,6 @@ async def test_reproducing_states(hass, caplog):
# These calls should do nothing as entities already in desired state # These calls should do nothing as entities already in desired state
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("remote.entity_off", "off"), State("remote.entity_on", "on")], [State("remote.entity_off", "off"), State("remote.entity_on", "on")],
blocking=True,
) )
assert len(turn_on_calls) == 0 assert len(turn_on_calls) == 0
@ -23,7 +22,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("remote.entity_off", "not_supported")], blocking=True [State("remote.entity_off", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -38,7 +37,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("remote.non_existing", "on"), State("remote.non_existing", "on"),
], ],
blocking=True,
) )
assert len(turn_on_calls) == 1 assert len(turn_on_calls) == 1

View file

@ -6,7 +6,7 @@ from homeassistant.components import light, scene
from homeassistant.setup import async_setup_component, setup_component from homeassistant.setup import async_setup_component, setup_component
from homeassistant.util.yaml import loader as yaml_loader from homeassistant.util.yaml import loader as yaml_loader
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant, mock_service
from tests.components.light import common as common_light from tests.components.light import common as common_light
from tests.components.scene import common from tests.components.scene import common
@ -127,7 +127,19 @@ class TestScene(unittest.TestCase):
assert self.light_1.is_on assert self.light_1.is_on
assert self.light_2.is_on assert self.light_2.is_on
assert 100 == self.light_2.last_call("turn_on")[1].get("brightness") assert self.light_2.last_call("turn_on")[1].get("brightness") == 100
turn_on_calls = mock_service(self.hass, "light", "turn_on")
self.hass.services.call(
scene.DOMAIN, "turn_on", {"transition": 42, "entity_id": "scene.test"}
)
self.hass.block_till_done()
assert len(turn_on_calls) == 1
assert turn_on_calls[0].domain == "light"
assert turn_on_calls[0].service == "turn_on"
assert turn_on_calls[0].data.get("transition") == 42
async def test_services_registered(hass): async def test_services_registered(hass):

View file

@ -15,7 +15,6 @@ async def test_reproducing_states(hass, caplog):
# These calls should do nothing as entities already in desired state # These calls should do nothing as entities already in desired state
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("switch.entity_off", "off"), State("switch.entity_on", "on", {})], [State("switch.entity_off", "off"), State("switch.entity_on", "on", {})],
blocking=True,
) )
assert len(turn_on_calls) == 0 assert len(turn_on_calls) == 0
@ -23,7 +22,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("switch.entity_off", "not_supported")], blocking=True [State("switch.entity_off", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -37,8 +36,7 @@ async def test_reproducing_states(hass, caplog):
State("switch.entity_off", "on", {}), State("switch.entity_off", "on", {}),
# Should not raise # Should not raise
State("switch.non_existing", "on"), State("switch.non_existing", "on"),
], ]
blocking=True,
) )
assert len(turn_on_calls) == 1 assert len(turn_on_calls) == 1

View file

@ -36,7 +36,6 @@ async def test_reproducing_states(hass, caplog):
"timer.entity_active_attr", STATUS_ACTIVE, {ATTR_DURATION: "00:01:00"} "timer.entity_active_attr", STATUS_ACTIVE, {ATTR_DURATION: "00:01:00"}
), ),
], ],
blocking=True,
) )
assert len(start_calls) == 0 assert len(start_calls) == 0
@ -45,7 +44,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("timer.entity_idle", "not_supported")], blocking=True [State("timer.entity_idle", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -63,7 +62,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("timer.non_existing", "on"), State("timer.non_existing", "on"),
], ],
blocking=True,
) )
valid_start_calls = [ valid_start_calls = [

View file

@ -59,7 +59,6 @@ async def test_reproducing_states(hass, caplog):
State("vacuum.entity_returning", STATE_RETURNING), State("vacuum.entity_returning", STATE_RETURNING),
State("vacuum.entity_paused", STATE_PAUSED), State("vacuum.entity_paused", STATE_PAUSED),
], ],
blocking=True,
) )
assert len(turn_on_calls) == 0 assert len(turn_on_calls) == 0
@ -72,7 +71,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("vacuum.entity_off", "not_supported")], blocking=True [State("vacuum.entity_off", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -98,7 +97,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("vacuum.non_existing", STATE_ON), State("vacuum.non_existing", STATE_ON),
], ],
blocking=True,
) )
assert len(turn_on_calls) == 1 assert len(turn_on_calls) == 1

View file

@ -45,8 +45,7 @@ async def test_reproducing_states(hass, caplog):
STATE_ECO, STATE_ECO,
{ATTR_AWAY_MODE: True, ATTR_TEMPERATURE: 45}, {ATTR_AWAY_MODE: True, ATTR_TEMPERATURE: 45},
), ),
], ]
blocking=True,
) )
assert len(turn_on_calls) == 0 assert len(turn_on_calls) == 0
@ -57,7 +56,7 @@ async def test_reproducing_states(hass, caplog):
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[State("water_heater.entity_off", "not_supported")], blocking=True [State("water_heater.entity_off", "not_supported")]
) )
assert "not_supported" in caplog.text assert "not_supported" in caplog.text
@ -82,7 +81,6 @@ async def test_reproducing_states(hass, caplog):
# Should not raise # Should not raise
State("water_heater.non_existing", "on"), State("water_heater.non_existing", "on"),
], ],
blocking=True,
) )
assert len(turn_on_calls) == 1 assert len(turn_on_calls) == 1

View file

@ -68,17 +68,16 @@ async def test_call_to_component(hass):
context = "dummy_context" context = "dummy_context"
await state.async_reproduce_state( await state.async_reproduce_state(
hass, hass, [state_media_player, state_climate], context=context,
[state_media_player, state_climate],
blocking=True,
context=context,
) )
media_player_fun.assert_called_once_with( media_player_fun.assert_called_once_with(
hass, [state_media_player], context=context hass, [state_media_player], context=context, reproduce_options=None
) )
climate_fun.assert_called_once_with(hass, [state_climate], context=context) climate_fun.assert_called_once_with(
hass, [state_climate], context=context, reproduce_options=None
)
async def test_get_changed_since(hass): async def test_get_changed_since(hass):