Skip to content

Commit

Permalink
Add lock util function to set multiple usercodes
Browse files Browse the repository at this point in the history
  • Loading branch information
raman325 committed Oct 10, 2024
1 parent 8ef40fa commit 89520fe
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 3 deletions.
42 changes: 42 additions & 0 deletions test/util/test_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
ATTR_IN_USE,
ATTR_NAME,
ATTR_USERCODE,
LOCK_USERCODE_ID_PROPERTY,
LOCK_USERCODE_PROPERTY,
LOCK_USERCODE_STATUS_PROPERTY,
CodeSlotStatus,
DoorLockCCConfigurationSetOptions,
OperationType,
)
Expand All @@ -24,6 +28,7 @@
get_usercodes,
set_configuration,
set_usercode,
set_usercodes,
)

from .const import CODE_SLOTS
Expand Down Expand Up @@ -102,6 +107,43 @@ async def test_set_usercode(lock_schlage_be469, mock_command, uuid4):
assert len(ack_commands) == 1


async def test_set_usercodes(lock_schlage_be469, mock_command, uuid4):
"""Test set_usercodes utility function."""
node = lock_schlage_be469
ack_commands = mock_command(
{"command": "endpoint.invoke_cc_api", "endpoint": 0, "nodeId": node.node_id},
{"response": {"status": 255}},
)

# Test wrong types to ensure values get converted
await set_usercodes(node, {"1": 1234})
assert len(ack_commands) == 1
assert ack_commands[0] == {
"command": "endpoint.invoke_cc_api",
"commandClass": 99,
"endpoint": 0,
"methodName": "setMany",
"nodeId": 20,
"messageId": uuid4,
"args": [
[
{
LOCK_USERCODE_STATUS_PROPERTY: CodeSlotStatus.ENABLED,
LOCK_USERCODE_ID_PROPERTY: 1,
LOCK_USERCODE_PROPERTY: "1234",
}
]
],
}

# Test invalid code length
with pytest.raises(ValueError):
await set_usercodes(node, {1: "123"})

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


async def test_clear_usercode(lock_schlage_be469, mock_command, uuid4):
"""Test clear_usercode utility function."""
node = lock_schlage_be469
Expand Down
1 change: 1 addition & 0 deletions zwave_js_server/const/command_class/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class CodeSlotStatus(IntEnum):

# User Code CC constants
LOCK_USERCODE_PROPERTY = "userCode"
LOCK_USERCODE_ID_PROPERTY = "userId"
LOCK_USERCODE_STATUS_PROPERTY = "userIdStatus"

ATTR_CODE_SLOT = "code_slot"
Expand Down
34 changes: 31 additions & 3 deletions zwave_js_server/util/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
CURRENT_BLOCK_TO_BLOCK_PROPERTY,
CURRENT_HOLD_AND_RELEASE_TIME_PROPERTY,
CURRENT_TWIST_ASSIST_PROPERTY,
LOCK_USERCODE_ID_PROPERTY,
LOCK_USERCODE_PROPERTY,
LOCK_USERCODE_STATUS_PROPERTY,
CodeSlotStatus,
Expand Down Expand Up @@ -68,7 +69,7 @@ def _get_code_slots(node: Node, include_usercode: bool = False) -> list[CodeSlot
except NotFoundError:
return slots

code_slot = int(value.property_key) # type: ignore[arg-type]
code_slot = int(value.property_key)
in_use = (
None
if status_value.value is None
Expand Down Expand Up @@ -104,7 +105,7 @@ def get_usercode(node: Node, code_slot: int) -> CodeSlot:
value = get_code_slot_value(node, code_slot, LOCK_USERCODE_PROPERTY)
status_value = get_code_slot_value(node, code_slot, LOCK_USERCODE_STATUS_PROPERTY)

code_slot = int(value.property_key) # type: ignore[arg-type]
code_slot = int(value.property_key)
in_use = (
None
if status_value.value is None
Expand All @@ -130,6 +131,7 @@ async def get_usercode_from_node(node: Node, code_slot: int) -> CodeSlot:
This call will populate the ValueDB and trigger value update events from the
driver.
"""
# https://zwave-js.github.io/node-zwave-js/#/api/CCs/UserCode?id=get
await node.async_invoke_cc_api(
CommandClass.USER_CODE, "get", code_slot, wait_for_result=True
)
Expand All @@ -141,13 +143,38 @@ async def set_usercode(
) -> SetValueResult | None:
"""Set the usercode to index X on the lock."""
value = get_code_slot_value(node, code_slot, LOCK_USERCODE_PROPERTY)
usercode = str(usercode)

if len(str(usercode)) < 4:
if len(usercode) < 4:
raise ValueError("User code must be at least 4 digits")

return await node.async_set_value(value, usercode)


async def set_usercodes(node: Node, codes: dict[int, str]) -> SetValueResult | None:
"""Set the usercode to index X on the lock."""
if any(len(str(usercode)) < 4 for usercode in codes.values()):
raise ValueError("User codes must be at least 4 digits")

codes_api = [
{
LOCK_USERCODE_ID_PROPERTY: int(code_slot),
LOCK_USERCODE_STATUS_PROPERTY: CodeSlotStatus.ENABLED,
LOCK_USERCODE_PROPERTY: str(usercode),
}
for code_slot, usercode in codes.items()
]

# https://zwave-js.github.io/node-zwave-js/#/api/CCs/UserCode?id=setmany
data = await node.async_invoke_cc_api(
CommandClass.USER_CODE, "setMany", codes_api, wait_for_result=True
)

if not data:
return None
return SupervisionResult(data)


async def clear_usercode(node: Node, code_slot: int) -> SetValueResult | None:
"""Clear a code slot on the lock."""
value = get_code_slot_value(node, code_slot, LOCK_USERCODE_STATUS_PROPERTY)
Expand Down Expand Up @@ -197,6 +224,7 @@ async def set_configuration(
if errors:
raise ValueError("\n".join(errors))

# https://zwave-js.github.io/node-zwave-js/#/api/CCs/UserCode?id=setconfiguration
data = await endpoint.async_invoke_cc_api(
CommandClass.DOOR_LOCK, "setConfiguration", configuration.to_dict()
)
Expand Down

0 comments on commit 89520fe

Please sign in to comment.