Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions test/util/test_node.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
"""Test node utility functions."""
import pytest

from zwave_js_server.const import CommandClass
from zwave_js_server.exceptions import InvalidNewValue, NotFoundError, ValueTypeError
from zwave_js_server.const import CommandClass, CommandStatus
from zwave_js_server.exceptions import (
InvalidNewValue,
NotFoundError,
SetValueFailed,
ValueTypeError,
)
from zwave_js_server.model.node import Node
from zwave_js_server.model.value import ConfigurationValue
from zwave_js_server.util.node import (
Expand Down Expand Up @@ -171,3 +176,44 @@ async def test_bulk_set_partial_config_parameters(multisensor_6, uuid4, mock_com
# Try to bulkset a property that isn't broken into partials
with pytest.raises(ValueTypeError):
await async_bulk_set_partial_config_parameters(node, 252, 1)


async def test_failures(multisensor_6, mock_command):
"""Test setting config parameter failures."""
node: Node = multisensor_6
# We need the node to be alive so we wait for a response
node.handle_alive(node)

_ = mock_command(
Comment thread
raman325 marked this conversation as resolved.
Outdated
{"command": "node.set_value", "nodeId": node.node_id},
{"success": False},
)

with pytest.raises(SetValueFailed):
await async_bulk_set_partial_config_parameters(
node, 101, {64: 1, 32: 1, 16: 1, 1: 1}
)

with pytest.raises(SetValueFailed):
await async_set_config_parameter(node, 1, 101, 64)


async def test_returned_values(multisensor_6, mock_command):
"""Test returned values from setting config parameters."""
node: Node = multisensor_6
# We need the node to be alive so we wait for a response
node.handle_alive(node)

_ = mock_command(
Comment thread
raman325 marked this conversation as resolved.
Outdated
{"command": "node.set_value", "nodeId": node.node_id},
{"success": True},
)

cmd_status = await async_bulk_set_partial_config_parameters(
node, 101, {64: 1, 32: 1, 16: 1, 1: 1}
)
assert cmd_status == CommandStatus.ACCEPTED

zwave_value, cmd_status = await async_set_config_parameter(node, 1, 101, 64)
assert isinstance(zwave_value, ConfigurationValue)
assert cmd_status == CommandStatus.ACCEPTED
8 changes: 8 additions & 0 deletions zwave_js_server/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@
VALUE_UNKNOWN = "unknown"


class CommandStatus(str, Enum):
"""Status of a command sent to zwave-js-server."""

ACCEPTED = "accepted"
QUEUED = "queued"
FAILED = "failed"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't seem to use the FAILED enum. Do we still need it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove it. I was thinking it would be nice in the future if, for queued messages, we could support an optional callback in the future that returned the result once the message was processed which is why I had added this. But I will remove it for now and we can discuss that separately



class EntryControlEventType(IntEnum):
"""Entry control event types."""

Expand Down
27 changes: 19 additions & 8 deletions zwave_js_server/util/node.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Utility functions for Z-Wave JS nodes."""
import json
from typing import Dict, Optional, Union, cast
from typing import Dict, Optional, Tuple, Union, cast

from ..const import CommandClass, ConfigurationValueType
from ..const import CommandClass, CommandStatus, ConfigurationValueType
from ..exceptions import InvalidNewValue, NotFoundError, SetValueFailed, ValueTypeError
from ..model.node import Node
from ..model.value import ConfigurationValue, get_value_id
Expand Down Expand Up @@ -88,7 +88,7 @@ async def async_bulk_set_partial_config_parameters(
node: Node,
property_: int,
new_value: Union[int, Dict[int, Union[int, str]]],
) -> None:
) -> CommandStatus:
"""Bulk set partial configuration values on this node."""
config_values = node.get_configuration_values()
property_values = [
Expand Down Expand Up @@ -153,28 +153,36 @@ async def async_bulk_set_partial_config_parameters(
remaining_value = remaining_value % multiplication_factor
_validate_and_transform_new_value(zwave_value, partial_value)

response = await node.async_send_command(
cmd_response = await node.async_send_command(
"set_value",
valueId={
"commandClass": CommandClass.CONFIGURATION.value,
"property": property_,
},
value=new_value,
)
if response and not cast(bool, response["success"]):

# If we didn't wait for a response, we assume the command has been queued
if cmd_response is None:
return CommandStatus.QUEUED

if not cast(bool, cmd_response["success"]):
raise SetValueFailed(
"Unable to set value, refer to "
"https://zwave-js.github.io/node-zwave-js/#/api/node?id=setvalue for "
"possible reasons"
)

# If we received a response that is not false, the command was successful
return CommandStatus.ACCEPTED


async def async_set_config_parameter(
node: Node,
new_value: Union[int, str],
property_or_property_name: Union[int, str],
property_key: Optional[Union[int, str]] = None,
) -> ConfigurationValue:
) -> Tuple[ConfigurationValue, CommandStatus]:
"""
Set a value for a config parameter on this node.

Expand Down Expand Up @@ -216,11 +224,14 @@ async def async_set_config_parameter(
new_value = _validate_and_transform_new_value(zwave_value, new_value)

# Finally attempt to set the value and return the Value object if successful
if await node.async_set_value(zwave_value, new_value) is False:
success = await node.async_set_value(zwave_value, new_value)
if success is False:
raise SetValueFailed(
"Unable to set value, refer to "
"https://zwave-js.github.io/node-zwave-js/#/api/node?id=setvalue for "
"possible reasons"
)

return zwave_value
status = CommandStatus.ACCEPTED if success else CommandStatus.QUEUED

return zwave_value, status