Skip to content

Commit

Permalink
Create endpoint version of command and refactor node commands
Browse files Browse the repository at this point in the history
  • Loading branch information
raman325 committed Oct 16, 2023
1 parent b925dd0 commit f05fd4a
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 68 deletions.
15 changes: 9 additions & 6 deletions test/model/test_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -2511,15 +2511,16 @@ async def test_set_raw_config_parameter_value(
node = multisensor_6

ack_commands = mock_command(
{"command": "node.set_raw_config_parameter_value", "nodeId": node.node_id},
{"command": "endpoint.set_raw_config_parameter_value", "nodeId": node.node_id},
{},
)

assert await node.async_set_raw_config_parameter_value(1, 101, 1) is None

assert ack_commands[0] == {
"command": "node.set_raw_config_parameter_value",
"command": "endpoint.set_raw_config_parameter_value",
"nodeId": node.node_id,
"endpoint": 0,
"options": {
"parameter": 101,
"bitMask": 1,
Expand All @@ -2536,8 +2537,9 @@ async def test_set_raw_config_parameter_value(
)

assert ack_commands[1] == {
"command": "node.set_raw_config_parameter_value",
"command": "endpoint.set_raw_config_parameter_value",
"nodeId": node.node_id,
"endpoint": 0,
"options": {
"parameter": 2,
"value": 0,
Expand All @@ -2553,8 +2555,9 @@ async def test_set_raw_config_parameter_value(
)

assert ack_commands[2] == {
"command": "node.set_raw_config_parameter_value",
"command": "endpoint.set_raw_config_parameter_value",
"nodeId": node.node_id,
"endpoint": 0,
"options": {
"parameter": 101,
"bitMask": 1,
Expand Down Expand Up @@ -2588,7 +2591,7 @@ async def test_supervision_result(inovelli_switch: node_pkg.Node, uuid4, mock_co
node = inovelli_switch

mock_command(
{"command": "node.set_raw_config_parameter_value", "nodeId": node.node_id},
{"command": "endpoint.set_raw_config_parameter_value", "nodeId": node.node_id},
{"result": {"status": 1, "remainingDuration": "default"}},
)

Expand All @@ -2605,7 +2608,7 @@ async def test_supervision_result_invalid(
node = inovelli_switch

mock_command(
{"command": "node.set_raw_config_parameter_value", "nodeId": node.node_id},
{"command": "endpoint.set_raw_config_parameter_value", "nodeId": node.node_id},
{"result": {"status": 1}},
)

Expand Down
92 changes: 90 additions & 2 deletions zwave_js_server/model/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
"""
from __future__ import annotations

from typing import TYPE_CHECKING, Any, TypedDict, cast
from typing import TYPE_CHECKING, Any, Literal, TypedDict, cast

from ..const import NodeStatus
from ..event import EventBase
from ..exceptions import FailedCommand, NotFoundError
from .command_class import CommandClass, CommandClassInfo, CommandClassInfoDataType
from .device_class import DeviceClass, DeviceClassDataType
from .value import ConfigurationValue, Value
from .value import ConfigurationValue, ConfigurationValueFormat, SupervisionResult, Value

if TYPE_CHECKING:
from ..client import Client
Expand Down Expand Up @@ -118,6 +118,23 @@ def update(
if value_id not in self.values:
self.values[value_id] = value

def get_command_class_values(
self, command_class: CommandClass
) -> dict[str, ConfigurationValue | Value]:
"""Return all values for a given command class."""
return {
value_id: value
for value_id, value in self.values.items()
if value.command_class == command_class
}

def get_configuration_values(self) -> dict[str, ConfigurationValue]:
"""Return all configuration values for an endpoint."""
return cast(
dict[str, ConfigurationValue],
self.get_command_class_values(CommandClass.CONFIGURATION),
)

async def async_send_command(
self,
cmd: str,
Expand Down Expand Up @@ -243,3 +260,74 @@ async def async_get_node_unsafe(self) -> "NodeDataType":
)
assert result
return cast("NodeDataType", result["node"])

async def async_set_raw_config_parameter_value(
self,
new_value: int | str,
property_: int | str,
property_key: int | None = None,
value_size: Literal[1, 2, 4] | None = None,
value_format: ConfigurationValueFormat | None = None,
) -> SupervisionResult | None:
"""Send setRawConfigParameterValue."""
try:
zwave_value = next(
config_value
for config_value in self.get_configuration_values().values()
if property_
== (
config_value.property_name
if isinstance(property_, str)
else config_value.property_
)
and property_key == config_value.property_key
)
except StopIteration:
raise NotFoundError(
f"Configuration parameter with parameter {property_} and bitmask "
f"{property_key} on node {self} could not be found"
) from None

if not isinstance(new_value, str):
value = new_value
else:
try:
value = int(
next(
k
for k, v in zwave_value.metadata.states.items()
if v == new_value
)
)
except StopIteration:
raise NotFoundError(
f"Configuration parameter {zwave_value.value_id} does not have "
f"{new_value} as a valid state. If this is a valid call, you must "
"use the state key instead of the string."
) from None

if (value_size is not None and value_format is None) or (
value_size is None and value_format is not None
):
raise ValueError(
"value_size and value_format must either both be included or not "
"included"
)

options = {
"value": value,
"parameter": zwave_value.property_,
"bitMask": zwave_value.property_key,
"valueSize": value_size,
"valueFormat": value_format,
}

data = await self.async_send_command(
"set_raw_config_parameter_value",
options={k: v for k, v in options.items() if v is not None},
require_schema=33,
)

if data is None or (result := data.get("result")) is None:
return None
return SupervisionResult(result)
62 changes: 2 additions & 60 deletions zwave_js_server/model/node/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,68 +952,10 @@ async def async_set_raw_config_parameter_value(
value_format: ConfigurationValueFormat | None = None,
) -> SupervisionResult | None:
"""Send setRawConfigParameterValue."""
try:
zwave_value = next(
config_value
for config_value in self.get_configuration_values().values()
if property_
== (
config_value.property_name
if isinstance(property_, str)
else config_value.property_
)
and property_key == config_value.property_key
)
except StopIteration:
raise NotFoundError(
f"Configuration parameter with parameter {property_} and bitmask "
f"{property_key} on node {self} could not be found"
) from None

if not isinstance(new_value, str):
value = new_value
else:
try:
value = int(
next(
k
for k, v in zwave_value.metadata.states.items()
if v == new_value
)
)
except StopIteration:
raise NotFoundError(
f"Configuration parameter {zwave_value.value_id} does not have "
f"{new_value} as a valid state. If this is a valid call, you must "
"use the state key instead of the string."
) from None

if (value_size is not None and value_format is None) or (
value_size is None and value_format is not None
):
raise ValueError(
"value_size and value_format must either both be included or not "
"included"
)

options = {
"value": value,
"parameter": zwave_value.property_,
"bitMask": zwave_value.property_key,
"valueSize": value_size,
"valueFormat": value_format,
}

data = await self.async_send_command(
"set_raw_config_parameter_value",
options={k: v for k, v in options.items() if v is not None},
require_schema=33,
return await self.endpoints[0].async_set_raw_config_parameter_value(
new_value, property_, property_key, value_size, value_format
)

if data is None or (result := data.get("result")) is None:
return None
return SupervisionResult(result)

def handle_test_powerlevel_progress(self, event: Event) -> None:
"""Process a test power level progress event."""
event.data["test_power_level_progress"] = TestPowerLevelProgress(
Expand Down

0 comments on commit f05fd4a

Please sign in to comment.