Skip to content

Commit

Permalink
Add ability to set Zwave protection commandclass (#15390)
Browse files Browse the repository at this point in the history
* Add API for protection commandclass

* Adjusting

* tests

* Spelling

* Missed flake8

* Period

* spelling

* Review changes

* removing additional .keys()

* period

* Move i/o out into executor pool

* Move i/o out into executor pool

* Forgot get method

* Do it right... I feel stupid

* Long lines

* Merging
  • Loading branch information
turbokongen authored and balloob committed Jul 23, 2018
1 parent 3204501 commit 1b94fe3
Show file tree
Hide file tree
Showing 2 changed files with 246 additions and 0 deletions.
57 changes: 57 additions & 0 deletions homeassistant/components/config/zwave.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -196,3 +197,59 @@ 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"

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)
189 changes: 189 additions & 0 deletions tests/components/config/test_zwave.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'}

0 comments on commit 1b94fe3

Please sign in to comment.