Skip to content

Commit

Permalink
Update lock util functions to handle changes in zwave-js 8.0.0 (#257)
Browse files Browse the repository at this point in the history
* Update lock util functions to handle changes in zwave-js 8.0.0

* Add tests and bugfixes

* mypy

* fix assertion

* rename helper function to something better

* Add return value to reduce calls

* Make it easier for code slot helper functions to advertise when a user code hasn't been queried

* fix docstring

* simplify logic

* Take advantage of the fact that node is endpoint subclass

* black
  • Loading branch information
raman325 authored Jul 22, 2021
1 parent 9bb1391 commit 7e2b122
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 35 deletions.
6 changes: 2 additions & 4 deletions test/fixtures/lock_schlage_be469_state.json
Original file line number Diff line number Diff line change
Expand Up @@ -1398,8 +1398,7 @@
"1": "Enabled",
"2": "Disabled"
}
},
"value": 0
}
},
{
"commandClassName": "User Code",
Expand All @@ -1416,8 +1415,7 @@
"minLength": 4,
"maxLength": 10,
"label": "User Code (30)"
},
"value": ""
}
},
{
"commandClassName": "Manufacturer Specific",
Expand Down
52 changes: 26 additions & 26 deletions test/util/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,155 +31,155 @@
ATTR_CODE_SLOT: 5,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (5)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 6,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (6)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 7,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (7)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 8,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (8)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 9,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (9)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 10,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (10)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 11,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (11)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 12,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (12)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 13,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (13)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 14,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (14)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 15,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (15)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 16,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (16)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 17,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (17)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 18,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (18)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 19,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (19)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 20,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (20)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 21,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (21)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 22,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (22)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 23,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (23)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 24,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (24)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 25,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (25)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 26,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (26)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 27,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (27)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 28,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (28)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 29,
ATTR_IN_USE: False,
ATTR_NAME: "User Code (29)",
ATTR_USERCODE: None,
ATTR_USERCODE: "",
},
{
ATTR_CODE_SLOT: 30,
ATTR_IN_USE: False,
ATTR_IN_USE: None,
ATTR_NAME: "User Code (30)",
ATTR_USERCODE: None,
},
Expand Down
31 changes: 30 additions & 1 deletion test/util/test_lock.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"""Test lock utility functions."""
import pytest

from zwave_js_server.const import ATTR_USERCODE
from zwave_js_server.const import ATTR_IN_USE, ATTR_USERCODE
from zwave_js_server.exceptions import NotFoundError
from zwave_js_server.util.lock import (
clear_usercode,
get_code_slots,
get_usercode,
get_usercodes,
get_usercode_from_node,
set_usercode,
)

Expand All @@ -32,6 +33,9 @@ def test_get_usercode(lock_schlage_be469):
assert all(char == "*" for char in user_code)

# Test unused slot
assert get_usercode(node, 29) == ""

# Test unknown slot
assert get_usercode(node, 30) is None

# Test invalid slot
Expand Down Expand Up @@ -141,3 +145,28 @@ async def test_clear_usercode(lock_schlage_be469, mock_command, uuid4):

# assert no new command calls
assert len(ack_commands) == 1


async def test_get_usercode_from_node(lock_schlage_be469, mock_command, uuid4):
"""Test get_usercode_from_node utility function."""
node = lock_schlage_be469
ack_commands = mock_command(
{"command": "endpoint.invoke_cc_api", "nodeId": node.node_id, "endpoint": 0},
{"response": {"userIdStatus": 1, "userCode": "**********"}},
)

# Test valid code
assert await get_usercode_from_node(node, 1) == {
ATTR_IN_USE: True,
ATTR_USERCODE: "**********",
}
assert len(ack_commands) == 1
assert ack_commands[0] == {
"command": "endpoint.invoke_cc_api",
"nodeId": 20,
"endpoint": 0,
"commandClass": 99,
"messageId": uuid4,
"methodName": "get",
"args": [1],
}
29 changes: 25 additions & 4 deletions zwave_js_server/util/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,21 @@ def _get_code_slots(
return slots

code_slot = int(value.property_key) # type: ignore
in_use = (
None
if status_value.value is None
else status_value.value == CodeSlotStatus.ENABLED
)

# we know that code slots will always have a property key
# that is an int, so we can ignore mypy
slot = {
ATTR_CODE_SLOT: code_slot,
ATTR_NAME: value.metadata.label,
ATTR_IN_USE: status_value.value == CodeSlotStatus.ENABLED,
ATTR_IN_USE: in_use,
}
if include_usercode:
slot[ATTR_USERCODE] = value.value if value.value else None
slot[ATTR_USERCODE] = value.value

slots.append(slot)
code_slot += 1
Expand All @@ -80,8 +85,24 @@ def get_usercodes(node: Node) -> List[Dict[str, Optional[Union[int, bool, str]]]
def get_usercode(node: Node, code_slot: int) -> Optional[str]:
"""Get usercode from slot X on the lock."""
value = get_code_slot_value(node, code_slot, LOCK_USERCODE_PROPERTY)

return str(value.value) if value.value else None
return value.value


async def get_usercode_from_node(
node: Node, code_slot: int
) -> Dict[str, Union[str, bool]]:
"""
Fetch a usercode directly from a node.
Should be used when Z-Wave JS's ValueDB hasn't been populated for this code slot.
This call will populate the ValueDB and trigger value update events from the
driver.
"""
resp = await node.async_invoke_cc_api(CommandClass.USER_CODE, "get", code_slot)
return {
ATTR_IN_USE: resp["userIdStatus"] == CodeSlotStatus.ENABLED,
ATTR_USERCODE: resp["userCode"],
}


async def set_usercode(node: Node, code_slot: int, usercode: str) -> None:
Expand Down

0 comments on commit 7e2b122

Please sign in to comment.