mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 18:27:09 +00:00
Add ability to set Zwave protection commandclass (#15390)
* 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
This commit is contained in:
parent
3204501174
commit
1b94fe3613
@ -29,6 +29,7 @@ def async_setup(hass):
|
|||||||
hass.http.register_view(ZWaveUserCodeView)
|
hass.http.register_view(ZWaveUserCodeView)
|
||||||
hass.http.register_view(ZWaveLogView)
|
hass.http.register_view(ZWaveLogView)
|
||||||
hass.http.register_view(ZWaveConfigWriteView)
|
hass.http.register_view(ZWaveConfigWriteView)
|
||||||
|
hass.http.register_view(ZWaveProtectionView)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -196,3 +197,59 @@ class ZWaveUserCodeView(HomeAssistantView):
|
|||||||
'label': value.label,
|
'label': value.label,
|
||||||
'length': len(value.data)}
|
'length': len(value.data)}
|
||||||
return self.json(usercodes)
|
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)
|
||||||
|
@ -367,3 +367,192 @@ def test_save_config(hass, client):
|
|||||||
result = yield from resp.json()
|
result = yield from resp.json()
|
||||||
assert network.write_config.called
|
assert network.write_config.called
|
||||||
assert result == {'message': 'Z-Wave configuration saved to file.'}
|
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'}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user