diff --git a/homeassistant/components/config/zwave.py b/homeassistant/components/config/zwave.py index c839ab7bc6e..84927712741 100644 --- a/homeassistant/components/config/zwave.py +++ b/homeassistant/components/config/zwave.py @@ -29,6 +29,7 @@ def async_setup(hass): hass.http.register_view(ZWaveUserCodeView) hass.http.register_view(ZWaveLogView) hass.http.register_view(ZWaveConfigWriteView) + hass.http.register_view(ZWaveProtectionView) return True @@ -196,3 +197,59 @@ class ZWaveUserCodeView(HomeAssistantView): 'label': value.label, 'length': len(value.data)} return self.json(usercodes) + + +class ZWaveProtectionView(HomeAssistantView): + """View for the protection commandclass of a node.""" + + url = r"/api/zwave/protection/{node_id:\d+}" + name = "api:zwave:protection" + + async def get(self, request, node_id): + """Retrieve the protection commandclass options of node.""" + nodeid = int(node_id) + hass = request.app['hass'] + network = hass.data.get(const.DATA_NETWORK) + + def _fetch_protection(): + """Helper to get protection data.""" + node = network.nodes.get(nodeid) + if node is None: + return self.json_message('Node not found', HTTP_NOT_FOUND) + protection_options = {} + if not node.has_command_class(const.COMMAND_CLASS_PROTECTION): + return self.json(protection_options) + protections = node.get_protections() + protection_options = { + 'value_id': '{0:d}'.format(list(protections)[0]), + 'selected': node.get_protection_item(list(protections)[0]), + 'options': node.get_protection_items(list(protections)[0])} + return self.json(protection_options) + + return await hass.async_add_executor_job(_fetch_protection) + + async def post(self, request, node_id): + """Change the selected option in protection commandclass.""" + nodeid = int(node_id) + hass = request.app['hass'] + network = hass.data.get(const.DATA_NETWORK) + protection_data = await request.json() + + def _set_protection(): + """Helper to get protection data.""" + node = network.nodes.get(nodeid) + selection = protection_data["selection"] + value_id = int(protection_data[const.ATTR_VALUE_ID]) + if node is None: + return self.json_message('Node not found', HTTP_NOT_FOUND) + if not node.has_command_class(const.COMMAND_CLASS_PROTECTION): + return self.json_message( + 'No protection commandclass on this node', HTTP_NOT_FOUND) + state = node.set_protection(value_id, selection) + if not state: + return self.json_message( + 'Protection setting did not complete', 202) + return self.json_message( + 'Protection setting succsessfully set', HTTP_OK) + + return await hass.async_add_executor_job(_set_protection) diff --git a/tests/components/config/test_zwave.py b/tests/components/config/test_zwave.py index 672bafeaf28..8aae5c0a28b 100644 --- a/tests/components/config/test_zwave.py +++ b/tests/components/config/test_zwave.py @@ -367,3 +367,192 @@ def test_save_config(hass, client): result = yield from resp.json() assert network.write_config.called assert result == {'message': 'Z-Wave configuration saved to file.'} + + +async def test_get_protection_values(hass, client): + """Test getting protection values on node.""" + network = hass.data[DATA_NETWORK] = MagicMock() + node = MockNode(node_id=18, + command_classes=[const.COMMAND_CLASS_PROTECTION]) + value = MockValue( + value_id=123456, + index=0, + instance=1, + command_class=const.COMMAND_CLASS_PROTECTION) + value.label = 'Protection Test' + value.data_items = ['Unprotected', 'Protection by Sequence', + 'No Operation Possible'] + value.data = 'Unprotected' + network.nodes = {18: node} + node.value = value + + node.get_protection_item.return_value = "Unprotected" + node.get_protection_items.return_value = value.data_items + node.get_protections.return_value = {value.value_id: 'Object'} + + resp = await client.get('/api/zwave/protection/18') + + assert resp.status == 200 + result = await resp.json() + assert node.get_protections.called + assert node.get_protection_item.called + assert node.get_protection_items.called + assert result == { + 'value_id': '123456', + 'selected': 'Unprotected', + 'options': ['Unprotected', 'Protection by Sequence', + 'No Operation Possible'] + } + + +async def test_get_protection_values_nonexisting_node(hass, client): + """Test getting protection values on node with wrong nodeid.""" + network = hass.data[DATA_NETWORK] = MagicMock() + node = MockNode(node_id=18, + command_classes=[const.COMMAND_CLASS_PROTECTION]) + value = MockValue( + value_id=123456, + index=0, + instance=1, + command_class=const.COMMAND_CLASS_PROTECTION) + value.label = 'Protection Test' + value.data_items = ['Unprotected', 'Protection by Sequence', + 'No Operation Possible'] + value.data = 'Unprotected' + network.nodes = {17: node} + node.value = value + + resp = await client.get('/api/zwave/protection/18') + + assert resp.status == 404 + result = await resp.json() + assert not node.get_protections.called + assert not node.get_protection_item.called + assert not node.get_protection_items.called + assert result == {'message': 'Node not found'} + + +async def test_get_protection_values_without_protectionclass(hass, client): + """Test getting protection values on node without protectionclass.""" + network = hass.data[DATA_NETWORK] = MagicMock() + node = MockNode(node_id=18) + value = MockValue( + value_id=123456, + index=0, + instance=1) + network.nodes = {18: node} + node.value = value + + resp = await client.get('/api/zwave/protection/18') + + assert resp.status == 200 + result = await resp.json() + assert not node.get_protections.called + assert not node.get_protection_item.called + assert not node.get_protection_items.called + assert result == {} + + +async def test_set_protection_value(hass, client): + """Test setting protection value on node.""" + network = hass.data[DATA_NETWORK] = MagicMock() + node = MockNode(node_id=18, + command_classes=[const.COMMAND_CLASS_PROTECTION]) + value = MockValue( + value_id=123456, + index=0, + instance=1, + command_class=const.COMMAND_CLASS_PROTECTION) + value.label = 'Protection Test' + value.data_items = ['Unprotected', 'Protection by Sequence', + 'No Operation Possible'] + value.data = 'Unprotected' + network.nodes = {18: node} + node.value = value + + resp = await client.post( + '/api/zwave/protection/18', data=json.dumps({ + 'value_id': '123456', 'selection': 'Protection by Sequence'})) + + assert resp.status == 200 + result = await resp.json() + assert node.set_protection.called + assert result == {'message': 'Protection setting succsessfully set'} + + +async def test_set_protection_value_failed(hass, client): + """Test setting protection value failed on node.""" + network = hass.data[DATA_NETWORK] = MagicMock() + node = MockNode(node_id=18, + command_classes=[const.COMMAND_CLASS_PROTECTION]) + value = MockValue( + value_id=123456, + index=0, + instance=1, + command_class=const.COMMAND_CLASS_PROTECTION) + value.label = 'Protection Test' + value.data_items = ['Unprotected', 'Protection by Sequence', + 'No Operation Possible'] + value.data = 'Unprotected' + network.nodes = {18: node} + node.value = value + node.set_protection.return_value = False + + resp = await client.post( + '/api/zwave/protection/18', data=json.dumps({ + 'value_id': '123456', 'selection': 'Protecton by Seuence'})) + + assert resp.status == 202 + result = await resp.json() + assert node.set_protection.called + assert result == {'message': 'Protection setting did not complete'} + + +async def test_set_protection_value_nonexisting_node(hass, client): + """Test setting protection value on nonexisting node.""" + network = hass.data[DATA_NETWORK] = MagicMock() + node = MockNode(node_id=17, + command_classes=[const.COMMAND_CLASS_PROTECTION]) + value = MockValue( + value_id=123456, + index=0, + instance=1, + command_class=const.COMMAND_CLASS_PROTECTION) + value.label = 'Protection Test' + value.data_items = ['Unprotected', 'Protection by Sequence', + 'No Operation Possible'] + value.data = 'Unprotected' + network.nodes = {17: node} + node.value = value + node.set_protection.return_value = False + + resp = await client.post( + '/api/zwave/protection/18', data=json.dumps({ + 'value_id': '123456', 'selection': 'Protecton by Seuence'})) + + assert resp.status == 404 + result = await resp.json() + assert not node.set_protection.called + assert result == {'message': 'Node not found'} + + +async def test_set_protection_value_missing_class(hass, client): + """Test setting protection value on node without protectionclass.""" + network = hass.data[DATA_NETWORK] = MagicMock() + node = MockNode(node_id=17) + value = MockValue( + value_id=123456, + index=0, + instance=1) + network.nodes = {17: node} + node.value = value + node.set_protection.return_value = False + + resp = await client.post( + '/api/zwave/protection/17', data=json.dumps({ + 'value_id': '123456', 'selection': 'Protecton by Seuence'})) + + assert resp.status == 404 + result = await resp.json() + assert not node.set_protection.called + assert result == {'message': 'No protection commandclass on this node'}