Add lock util function to set multiple usercodes (#1089)
* Add lock util function to set multiple usercodes * restore ignores * Add coverage * rename * Update test/util/test_lock.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update test/util/test_lock.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update lock.py * Update lock.py --------- Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
8ef40fa462
commit
33881bd2b2
|
@ -11,11 +11,16 @@ from zwave_js_server.const.command_class.lock import (
|
|||
ATTR_IN_USE,
|
||||
ATTR_NAME,
|
||||
ATTR_USERCODE,
|
||||
LOCK_USERCODE_ID_PROPERTY,
|
||||
LOCK_USERCODE_PROPERTY,
|
||||
LOCK_USERCODE_STATUS_PROPERTY,
|
||||
CodeSlotStatus,
|
||||
DoorLockCCConfigurationSetOptions,
|
||||
OperationType,
|
||||
)
|
||||
from zwave_js_server.exceptions import NotFoundError
|
||||
from zwave_js_server.model.node import Node
|
||||
from zwave_js_server.model.value import SupervisionResult
|
||||
from zwave_js_server.util.lock import (
|
||||
clear_usercode,
|
||||
get_code_slots,
|
||||
|
@ -24,6 +29,7 @@ from zwave_js_server.util.lock import (
|
|||
get_usercodes,
|
||||
set_configuration,
|
||||
set_usercode,
|
||||
set_usercodes,
|
||||
)
|
||||
|
||||
from .const import CODE_SLOTS
|
||||
|
@ -102,6 +108,61 @@ async def test_set_usercode(lock_schlage_be469, mock_command, uuid4):
|
|||
assert len(ack_commands) == 1
|
||||
|
||||
|
||||
async def test_set_usercodes(
|
||||
lock_schlage_be469: Node, mock_command: MockCommandProtocol, uuid4: str
|
||||
) -> None:
|
||||
"""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
|
||||
assert await set_usercodes(node, {"1": 1234}) == SupervisionResult(
|
||||
{"status": SupervisionStatus.SUCCESS}
|
||||
)
|
||||
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_set_usercodes_invalid(
|
||||
lock_schlage_be469: Node, mock_command: MockCommandProtocol
|
||||
) -> None:
|
||||
"""Test set_usercodes utility function with invalid response."""
|
||||
node = lock_schlage_be469
|
||||
mock_command(
|
||||
{"command": "endpoint.invoke_cc_api", "endpoint": 0, "nodeId": node.node_id},
|
||||
{"response": {}},
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
assert await set_usercodes(node, {"1": 1234})
|
||||
|
||||
|
||||
async def test_clear_usercode(lock_schlage_be469, mock_command, uuid4):
|
||||
"""Test clear_usercode utility function."""
|
||||
node = lock_schlage_be469
|
||||
|
|
|
@ -118,6 +118,7 @@ LOCKED_PROPERTY = "locked"
|
|||
|
||||
# User Code CC constants
|
||||
LOCK_USERCODE_PROPERTY = "userCode"
|
||||
LOCK_USERCODE_ID_PROPERTY = "userId"
|
||||
LOCK_USERCODE_STATUS_PROPERTY = "userIdStatus"
|
||||
|
||||
ATTR_CODE_SLOT = "code_slot"
|
||||
|
|
|
@ -14,6 +14,7 @@ from ..const.command_class.lock import (
|
|||
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,
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -141,13 +143,40 @@ 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]) -> SupervisionResult | None:
|
||||
"""Set the usercode to index X on the lock."""
|
||||
cc_api_codes = [
|
||||
{
|
||||
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()
|
||||
if len(str(usercode)) >= 4
|
||||
]
|
||||
|
||||
if len(cc_api_codes) < len(codes):
|
||||
raise ValueError("User codes must be at least 4 digits")
|
||||
|
||||
# https://zwave-js.github.io/node-zwave-js/#/api/CCs/UserCode?id=setmany
|
||||
data = await node.async_invoke_cc_api(
|
||||
CommandClass.USER_CODE, "setMany", cc_api_codes, wait_for_result=True
|
||||
)
|
||||
|
||||
if not data:
|
||||
raise ValueError("Received unexpected response from User Code CC setMany API")
|
||||
|
||||
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)
|
||||
|
@ -197,6 +226,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()
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue