diff --git a/homeassistant/components/rollershutter/__init__.py b/homeassistant/components/rollershutter/__init__.py index c5fcb594f31..7d8b8235ed6 100644 --- a/homeassistant/components/rollershutter/__init__.py +++ b/homeassistant/components/rollershutter/__init__.py @@ -16,7 +16,7 @@ from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa import homeassistant.helpers.config_validation as cv from homeassistant.components import group from homeassistant.const import ( - SERVICE_MOVE_UP, SERVICE_MOVE_DOWN, SERVICE_STOP, + SERVICE_MOVE_UP, SERVICE_MOVE_DOWN, SERVICE_MOVE_POSITION, SERVICE_STOP, STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN, ATTR_ENTITY_ID) @@ -32,11 +32,17 @@ ENTITY_ID_FORMAT = DOMAIN + '.{}' _LOGGER = logging.getLogger(__name__) ATTR_CURRENT_POSITION = 'current_position' +ATTR_POSITION = 'position' ROLLERSHUTTER_SERVICE_SCHEMA = vol.Schema({ vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, }) +ROLLERSHUTTER_MOVE_POSITION_SCHEMA = ROLLERSHUTTER_SERVICE_SCHEMA.extend({ + vol.Required(ATTR_POSITION): + vol.All(vol.Coerce(int), vol.Range(min=0, max=100)), +}) + def is_open(hass, entity_id=None): """Return if the roller shutter is open based on the statemachine.""" @@ -56,6 +62,13 @@ def move_down(hass, entity_id=None): hass.services.call(DOMAIN, SERVICE_MOVE_DOWN, data) +def move_position(hass, position, entity_id=None): + """Move to specific position all or specified roller shutter.""" + data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} + data[ATTR_POSITION] = position + hass.services.call(DOMAIN, SERVICE_MOVE_POSITION, data) + + def stop(hass, entity_id=None): """Stop all or specified roller shutter.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None @@ -77,6 +90,8 @@ def setup(hass, config): rollershutter.move_up() elif service.service == SERVICE_MOVE_DOWN: rollershutter.move_down() + elif service.service == SERVICE_MOVE_POSITION: + rollershutter.move_position(service.data[ATTR_POSITION]) elif service.service == SERVICE_STOP: rollershutter.stop() @@ -94,6 +109,10 @@ def setup(hass, config): handle_rollershutter_service, descriptions.get(SERVICE_MOVE_DOWN), schema=ROLLERSHUTTER_SERVICE_SCHEMA) + hass.services.register(DOMAIN, SERVICE_MOVE_POSITION, + handle_rollershutter_service, + descriptions.get(SERVICE_MOVE_POSITION), + schema=ROLLERSHUTTER_MOVE_POSITION_SCHEMA) hass.services.register(DOMAIN, SERVICE_STOP, handle_rollershutter_service, descriptions.get(SERVICE_STOP), @@ -143,6 +162,10 @@ class RollershutterDevice(Entity): """Move the roller shutter up.""" raise NotImplementedError() + def move_position(self, **kwargs): + """Move the roller shutter to a specific position.""" + raise NotImplementedError() + def stop(self, **kwargs): """Stop the roller shutter.""" raise NotImplementedError() diff --git a/homeassistant/components/rollershutter/command_line.py b/homeassistant/components/rollershutter/command_line.py index c90a8be9410..976992e0061 100644 --- a/homeassistant/components/rollershutter/command_line.py +++ b/homeassistant/components/rollershutter/command_line.py @@ -32,6 +32,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): add_devices_callback(devices) +# pylint: disable=abstract-method # pylint: disable=too-many-arguments, too-many-instance-attributes class CommandRollershutter(RollershutterDevice): """Representation a command line roller shutter.""" diff --git a/homeassistant/components/rollershutter/demo.py b/homeassistant/components/rollershutter/demo.py index ebdc3907a59..31915019c5e 100644 --- a/homeassistant/components/rollershutter/demo.py +++ b/homeassistant/components/rollershutter/demo.py @@ -60,6 +60,14 @@ class DemoRollershutter(RollershutterDevice): self._listen() self._moving_up = False + def move_position(self, position, **kwargs): + """Move the roller shutter to a specific position.""" + if self._position == position: + return + + self._listen() + self._moving_up = position < self._position + def stop(self, **kwargs): """Stop the roller shutter.""" if self._listener is not None: diff --git a/homeassistant/components/rollershutter/homematic.py b/homeassistant/components/rollershutter/homematic.py index 9bdad7ee68c..805c5dceb82 100644 --- a/homeassistant/components/rollershutter/homematic.py +++ b/homeassistant/components/rollershutter/homematic.py @@ -30,6 +30,7 @@ def setup_platform(hass, config, add_callback_devices, discovery_info=None): add_callback_devices) +# pylint: disable=abstract-method class HMRollershutter(homematic.HMDevice, RollershutterDevice): """Represents a Homematic Rollershutter in Home Assistant.""" diff --git a/homeassistant/components/rollershutter/mqtt.py b/homeassistant/components/rollershutter/mqtt.py index 6465c02dca2..d0183da7a0f 100644 --- a/homeassistant/components/rollershutter/mqtt.py +++ b/homeassistant/components/rollershutter/mqtt.py @@ -52,6 +52,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): )]) +# pylint: disable=abstract-method # pylint: disable=too-many-arguments, too-many-instance-attributes class MqttRollershutter(RollershutterDevice): """Representation of a roller shutter that can be controlled using MQTT.""" diff --git a/homeassistant/components/rollershutter/rfxtrx.py b/homeassistant/components/rollershutter/rfxtrx.py index 18a2844b19c..19bcea4e892 100644 --- a/homeassistant/components/rollershutter/rfxtrx.py +++ b/homeassistant/components/rollershutter/rfxtrx.py @@ -40,6 +40,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): rfxtrx.RECEIVED_EVT_SUBSCRIBERS.append(rollershutter_update) +# pylint: disable=abstract-method class RfxtrxRollershutter(rfxtrx.RfxtrxDevice, RollershutterDevice): """Representation of an rfxtrx roller shutter.""" diff --git a/homeassistant/components/rollershutter/scsgate.py b/homeassistant/components/rollershutter/scsgate.py index 078173e1924..e67395d054c 100644 --- a/homeassistant/components/rollershutter/scsgate.py +++ b/homeassistant/components/rollershutter/scsgate.py @@ -37,6 +37,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): add_devices_callback(rollershutters) +# pylint: disable=abstract-method # pylint: disable=too-many-arguments, too-many-instance-attributes class SCSGateRollerShutter(RollershutterDevice): """Representation of SCSGate rollershutter.""" diff --git a/homeassistant/components/rollershutter/services.yaml b/homeassistant/components/rollershutter/services.yaml index b7ef0a17643..2991693961b 100644 --- a/homeassistant/components/rollershutter/services.yaml +++ b/homeassistant/components/rollershutter/services.yaml @@ -14,6 +14,14 @@ move_down: description: Name(s) of roller shutter(s) to move down example: 'rollershutter.living_room' +move_position: + description: Move to specific position all or specified roller shutter + + fields: + position: + description: Position of the rollershutter (0 to 100) + example: 30 + stop: description: Stop all or specified roller shutter diff --git a/homeassistant/components/rollershutter/wink.py b/homeassistant/components/rollershutter/wink.py index 8a791ea9b97..e18a75082a7 100644 --- a/homeassistant/components/rollershutter/wink.py +++ b/homeassistant/components/rollershutter/wink.py @@ -32,6 +32,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): pywink.get_shades()) +# pylint: disable=abstract-method class WinkRollershutterDevice(WinkDevice, RollershutterDevice): """Representation of a Wink rollershutter (shades).""" diff --git a/homeassistant/components/rollershutter/zwave.py b/homeassistant/components/rollershutter/zwave.py index 01d6980a795..efe93b3db79 100644 --- a/homeassistant/components/rollershutter/zwave.py +++ b/homeassistant/components/rollershutter/zwave.py @@ -97,6 +97,10 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, RollershutterDevice): self._lozwmgr.pressButton(value.value_id) break + def move_position(self, position, **kwargs): + """Move the roller shutter to a specific position.""" + self._node.set_dimmer(self._value.value_id, 100 - position) + def stop(self, **kwargs): """Stop the roller shutter.""" for value in self._node.get_values( diff --git a/homeassistant/const.py b/homeassistant/const.py index 65ff03b5276..61de02041b2 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -221,6 +221,7 @@ SERVICE_CLOSE = "close" SERVICE_MOVE_UP = 'move_up' SERVICE_MOVE_DOWN = 'move_down' +SERVICE_MOVE_POSITION = 'move_position' SERVICE_STOP = 'stop' # #### API / REMOTE #### diff --git a/tests/components/rollershutter/test_demo.py b/tests/components/rollershutter/test_demo.py new file mode 100644 index 00000000000..039221fad6e --- /dev/null +++ b/tests/components/rollershutter/test_demo.py @@ -0,0 +1,55 @@ +"""The tests for the Demo roller shutter platform.""" +import unittest +import homeassistant.util.dt as dt_util + +from homeassistant.components.rollershutter import demo +from tests.common import fire_time_changed, get_test_home_assistant + + +class TestRollershutterDemo(unittest.TestCase): + """Test the Demo roller shutter.""" + + def setUp(self): # pylint: disable=invalid-name + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + def tearDown(self): # pylint: disable=invalid-name + """Stop down everything that was started.""" + self.hass.stop() + + def test_move_up(self): + """Test moving the rollershutter up.""" + entity = demo.DemoRollershutter(self.hass, 'test', 100) + entity.move_up() + + fire_time_changed(self.hass, dt_util.utcnow()) + self.hass.pool.block_till_done() + self.assertEqual(90, entity.current_position) + + def test_move_down(self): + """Test moving the rollershutter down.""" + entity = demo.DemoRollershutter(self.hass, 'test', 0) + entity.move_down() + + fire_time_changed(self.hass, dt_util.utcnow()) + self.hass.pool.block_till_done() + self.assertEqual(10, entity.current_position) + + def test_move_position(self): + """Test moving the rollershutter to a specific position.""" + entity = demo.DemoRollershutter(self.hass, 'test', 0) + entity.move_position(10) + + fire_time_changed(self.hass, dt_util.utcnow()) + self.hass.pool.block_till_done() + self.assertEqual(10, entity.current_position) + + def test_stop(self): + """Test stopping the rollershutter.""" + entity = demo.DemoRollershutter(self.hass, 'test', 0) + entity.move_down() + entity.stop() + + fire_time_changed(self.hass, dt_util.utcnow()) + self.hass.pool.block_till_done() + self.assertEqual(0, entity.current_position)