-
-
Notifications
You must be signed in to change notification settings - Fork 38.2k
Add ability to set Zwave protection commandclass #15390
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
eb842c9
5992021
9ada5b7
715876d
5cc1123
a4ea0da
48659b1
25f3445
2b6dcb0
c3b554e
87be611
c13812d
bda7376
6fabf3b
7f448d8
e1d74a2
a2d1437
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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,51 @@ def get(self, request, node_id): | |
| '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" | ||
|
|
||
| @ha.callback | ||
| 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) | ||
| 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.keys())[0]), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need the |
||
| 'selected': node.get_protection_item(list(protections.keys())[0]), | ||
| 'options': node.get_protection_items(list(protections.keys())[0])} | ||
| return self.json(protection_options) | ||
|
|
||
| async def post(self, request, node_id): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too many blank lines (2) |
||
| """Change the selected option in protection commandclass.""" | ||
| nodeid = int(node_id) | ||
| hass = request.app['hass'] | ||
| network = hass.data.get(const.DATA_NETWORK) | ||
| node = network.nodes.get(nodeid) | ||
| protection_data = await request.json() | ||
|
|
||
| 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) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is doing I/O ? |
||
| if not state: | ||
| return self.json_message( | ||
| 'Protection setting did not complete', 202) | ||
| return self.json_message( | ||
| 'Protection setting succsessfully set', HTTP_OK) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -367,3 +367,199 @@ 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.'} | ||
|
|
||
|
|
||
| @asyncio.coroutine | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the Python 3.5 async syntax instead. |
||
| 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 = yield from client.get('/api/zwave/protection/18') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too many blank lines (2)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
|
|
||
| assert resp.status == 200 | ||
| result = yield from 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'] | ||
| } | ||
|
|
||
|
|
||
| @asyncio.coroutine | ||
| 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 = yield from client.get('/api/zwave/protection/18') | ||
|
|
||
| assert resp.status == 404 | ||
| result = yield from 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'} | ||
|
|
||
|
|
||
| @asyncio.coroutine | ||
| 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 = yield from client.get('/api/zwave/protection/18') | ||
|
|
||
| assert resp.status == 200 | ||
| result = yield from resp.json() | ||
| assert not node.get_protections.called | ||
| assert not node.get_protection_item.called | ||
| assert not node.get_protection_items.called | ||
| assert result == {} | ||
|
|
||
|
|
||
| @asyncio.coroutine | ||
| 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 = yield from client.post( | ||
| '/api/zwave/protection/18', data=json.dumps({ | ||
| 'value_id': '123456', 'selection': 'Protection by Sequence'})) | ||
|
|
||
| assert resp.status == 200 | ||
| result = yield from resp.json() | ||
| assert node.set_protection.called | ||
| assert result == {'message': 'Protection setting succsessfully set'} | ||
|
|
||
|
|
||
| @asyncio.coroutine | ||
| 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 = yield from client.post( | ||
| '/api/zwave/protection/18', data=json.dumps({ | ||
| 'value_id': '123456', 'selection': 'Protecton by Seuence'})) | ||
|
|
||
| assert resp.status == 202 | ||
| result = yield from resp.json() | ||
| assert node.set_protection.called | ||
| assert result == {'message': 'Protection setting did not complete'} | ||
|
|
||
|
|
||
| @asyncio.coroutine | ||
| 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 = yield from client.post( | ||
| '/api/zwave/protection/18', data=json.dumps({ | ||
| 'value_id': '123456', 'selection': 'Protecton by Seuence'})) | ||
|
|
||
| assert resp.status == 404 | ||
| result = yield from resp.json() | ||
| assert not node.set_protection.called | ||
| assert result == {'message': 'Node not found'} | ||
|
|
||
|
|
||
| @asyncio.coroutine | ||
| 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 = yield from client.post( | ||
| '/api/zwave/protection/17', data=json.dumps({ | ||
| 'value_id': '123456', 'selection': 'Protecton by Seuence'})) | ||
|
|
||
| assert resp.status == 404 | ||
| result = yield from resp.json() | ||
| assert not node.set_protection.called | ||
| assert result == {'message': 'No protection commandclass on this node'} | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is doing I/O ?