From 96d35379f286e465ac2383fd0c7d436092ab9427 Mon Sep 17 00:00:00 2001 From: Rolf K Date: Sat, 12 Oct 2019 20:46:09 +0200 Subject: [PATCH] Add improved scene support to input number integration (#27530) * Added improved scene support to the input_number integration. * Minor fix in test. * Use snake case for variable names in test_reproduce_state. * Remove redundant tests. --- .../input_number/reproduce_state.py | 52 ++++++++++++++++ .../input_number/test_reproduce_state.py | 62 +++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 homeassistant/components/input_number/reproduce_state.py create mode 100644 tests/components/input_number/test_reproduce_state.py diff --git a/homeassistant/components/input_number/reproduce_state.py b/homeassistant/components/input_number/reproduce_state.py new file mode 100644 index 00000000000..97a4837d371 --- /dev/null +++ b/homeassistant/components/input_number/reproduce_state.py @@ -0,0 +1,52 @@ +"""Reproduce an Input number state.""" +import asyncio +import logging +from typing import Iterable, Optional + +from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.core import Context, State +from homeassistant.helpers.typing import HomeAssistantType + +from . import DOMAIN, SERVICE_SET_VALUE, ATTR_VALUE + +_LOGGER = logging.getLogger(__name__) + + +async def _async_reproduce_state( + hass: HomeAssistantType, state: State, context: Optional[Context] = None +) -> None: + """Reproduce a single state.""" + cur_state = hass.states.get(state.entity_id) + + if cur_state is None: + _LOGGER.warning("Unable to find entity %s", state.entity_id) + return + + try: + float(state.state) + except ValueError: + _LOGGER.warning( + "Invalid state specified for %s: %s", state.entity_id, state.state + ) + return + + # Return if we are already at the right state. + if cur_state.state == state.state: + return + + service = SERVICE_SET_VALUE + service_data = {ATTR_ENTITY_ID: state.entity_id, ATTR_VALUE: state.state} + + await hass.services.async_call( + DOMAIN, service, service_data, context=context, blocking=True + ) + + +async def async_reproduce_states( + hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None +) -> None: + """Reproduce Input number states.""" + # Reproduce states in parallel. + await asyncio.gather( + *(_async_reproduce_state(hass, state, context) for state in states) + ) diff --git a/tests/components/input_number/test_reproduce_state.py b/tests/components/input_number/test_reproduce_state.py new file mode 100644 index 00000000000..37ab83f3204 --- /dev/null +++ b/tests/components/input_number/test_reproduce_state.py @@ -0,0 +1,62 @@ +"""Test reproduce state for Input number.""" +from homeassistant.core import State +from homeassistant.setup import async_setup_component + +VALID_NUMBER1 = "19.0" +VALID_NUMBER2 = "99.9" + + +async def test_reproducing_states(hass, caplog): + """Test reproducing Input number states.""" + + assert await async_setup_component( + hass, + "input_number", + { + "input_number": { + "test_number": {"min": "5", "max": "100", "initial": VALID_NUMBER1} + } + }, + ) + + # These calls should do nothing as entities already in desired state + await hass.helpers.state.async_reproduce_state( + [ + State("input_number.test_number", VALID_NUMBER1), + # Should not raise + State("input_number.non_existing", "234"), + ], + blocking=True, + ) + + assert hass.states.get("input_number.test_number").state == VALID_NUMBER1 + + # Test reproducing with different state + await hass.helpers.state.async_reproduce_state( + [ + State("input_number.test_number", VALID_NUMBER2), + # Should not raise + State("input_number.non_existing", "234"), + ], + blocking=True, + ) + + assert hass.states.get("input_number.test_number").state == VALID_NUMBER2 + + # Test setting state to number out of range + await hass.helpers.state.async_reproduce_state( + [State("input_number.test_number", "150")], blocking=True + ) + + # The entity states should be unchanged after trying to set them to out-of-range number + assert hass.states.get("input_number.test_number").state == VALID_NUMBER2 + + await hass.helpers.state.async_reproduce_state( + [ + # Test invalid state + State("input_number.test_number", "invalid_state"), + # Set to state it already is. + State("input_number.test_number", VALID_NUMBER2), + ], + blocking=True, + )