1 """Representation of Z-Wave locks."""
3 from __future__
import annotations
7 import voluptuous
as vol
8 from zwave_js_server.client
import Client
as ZwaveClient
9 from zwave_js_server.const
import CommandClass
10 from zwave_js_server.const.command_class.lock
import (
13 LOCK_CMD_CLASS_TO_LOCKED_STATE_MAP,
14 LOCK_CMD_CLASS_TO_PROPERTY_MAP,
15 DoorLockCCConfigurationSetOptions,
19 from zwave_js_server.exceptions
import BaseZwaveJSServerError
20 from zwave_js_server.util.lock
import clear_usercode, set_configuration, set_usercode
31 ATTR_AUTO_RELOCK_TIME,
33 ATTR_HOLD_AND_RELEASE_TIME,
40 SERVICE_CLEAR_LOCK_USERCODE,
41 SERVICE_SET_LOCK_CONFIGURATION,
42 SERVICE_SET_LOCK_USERCODE,
44 from .discovery
import ZwaveDiscoveryInfo
45 from .entity
import ZWaveBaseEntity
49 STATE_TO_ZWAVE_MAP: dict[int, dict[str, int | bool]] = {
50 CommandClass.DOOR_LOCK: {
51 LockState.UNLOCKED: DoorLockMode.UNSECURED,
52 LockState.LOCKED: DoorLockMode.SECURED,
55 LockState.UNLOCKED:
False,
56 LockState.LOCKED:
True,
59 UNIT16_SCHEMA = vol.All(vol.Coerce(int), vol.Range(min=0, max=65535))
64 config_entry: ConfigEntry,
65 async_add_entities: AddEntitiesCallback,
67 """Set up Z-Wave lock from config entry."""
68 client: ZwaveClient = config_entry.runtime_data[DATA_CLIENT]
71 def async_add_lock(info: ZwaveDiscoveryInfo) ->
None:
72 """Add Z-Wave Lock."""
73 driver = client.driver
74 assert driver
is not None
75 entities: list[ZWaveBaseEntity] = []
76 entities.append(
ZWaveLock(config_entry, driver, info))
80 config_entry.async_on_unload(
82 hass, f
"{DOMAIN}_{config_entry.entry_id}_add_{LOCK_DOMAIN}", async_add_lock
86 platform = entity_platform.async_get_current_platform()
88 platform.async_register_entity_service(
89 SERVICE_SET_LOCK_USERCODE,
91 vol.Required(ATTR_CODE_SLOT): vol.Coerce(int),
92 vol.Required(ATTR_USERCODE): cv.string,
94 "async_set_lock_usercode",
97 platform.async_register_entity_service(
98 SERVICE_CLEAR_LOCK_USERCODE,
100 vol.Required(ATTR_CODE_SLOT): vol.Coerce(int),
102 "async_clear_lock_usercode",
105 platform.async_register_entity_service(
106 SERVICE_SET_LOCK_CONFIGURATION,
108 vol.Required(ATTR_OPERATION_TYPE): vol.All(
111 vol.In([
"TIMED",
"CONSTANT"]),
112 lambda x: OperationType[x],
114 vol.Optional(ATTR_LOCK_TIMEOUT): UNIT16_SCHEMA,
115 vol.Optional(ATTR_AUTO_RELOCK_TIME): UNIT16_SCHEMA,
116 vol.Optional(ATTR_HOLD_AND_RELEASE_TIME): UNIT16_SCHEMA,
117 vol.Optional(ATTR_TWIST_ASSIST): vol.Coerce(bool),
118 vol.Optional(ATTR_BLOCK_TO_BLOCK): vol.Coerce(bool),
120 "async_set_lock_configuration",
125 """Representation of a Z-Wave lock."""
129 """Return true if the lock is locked."""
130 value = self.
infoinfo.primary_value
131 if value.value
is None or (
132 value.command_class == CommandClass.DOOR_LOCK
133 and value.value == DoorLockMode.UNKNOWN
138 LOCK_CMD_CLASS_TO_LOCKED_STATE_MAP[CommandClass(value.command_class)]
139 == self.
infoinfo.primary_value.value
143 """Set the lock state."""
145 LOCK_CMD_CLASS_TO_PROPERTY_MAP[
146 CommandClass(self.
infoinfo.primary_value.command_class)
149 if target_value
is not None:
152 STATE_TO_ZWAVE_MAP[self.
infoinfo.primary_value.command_class][target_state],
160 """Unlock the lock."""
164 """Set the usercode to index X on the lock."""
166 await set_usercode(self.
infoinfo.node, code_slot, usercode)
167 except BaseZwaveJSServerError
as err:
169 f
"Unable to set lock usercode on lock {self.entity_id} code_slot "
170 f
"{code_slot}: {err}"
172 LOGGER.debug(
"User code at slot %s on lock %s set", code_slot, self.
entity_identity_id)
175 """Clear the usercode at index X on the lock."""
177 await clear_usercode(self.
infoinfo.node, code_slot)
178 except BaseZwaveJSServerError
as err:
180 f
"Unable to clear lock usercode on lock {self.entity_id} code_slot "
181 f
"{code_slot}: {err}"
184 "User code at slot %s on lock %s cleared", code_slot, self.
entity_identity_id
189 operation_type: OperationType,
190 lock_timeout: int |
None =
None,
191 auto_relock_time: int |
None =
None,
192 hold_and_release_time: int |
None =
None,
193 twist_assist: bool |
None =
None,
194 block_to_block: bool |
None =
None,
196 """Set the lock configuration."""
197 params: dict[str, Any] = {
"operation_type": operation_type}
202 (
"lock_timeout_configuration", lock_timeout),
203 (
"auto_relock_time", auto_relock_time),
204 (
"hold_and_release_time", hold_and_release_time),
205 (
"twist_assist", twist_assist),
206 (
"block_to_block", block_to_block),
211 configuration = DoorLockCCConfigurationSetOptions(**params)
212 result = await set_configuration(
213 self.
infoinfo.node.endpoints[self.
infoinfo.primary_value.endpoint
or 0],
218 msg = f
"Result status is {result.status}"
219 if result.remaining_duration
is not None:
220 msg += f
" and remaining duration is {result.remaining_duration!s}"
221 LOGGER.info(
"%s after setting lock configuration for %s", msg, self.
entity_identity_id)
SetValueResult|None _async_set_value(self, ZwaveValue value, Any new_value, dict|None options=None, bool|None wait_for_result=None)
ZwaveValue|None get_zwave_value(self, str|int value_property, int|None command_class=None, int|None endpoint=None, int|str|None value_property_key=None, bool add_to_watched_value_ids=True, bool check_all_endpoints=False)
bool|None is_locked(self)
None _set_lock_state(self, LockState target_state, **Any kwargs)
None async_set_lock_configuration(self, OperationType operation_type, int|None lock_timeout=None, int|None auto_relock_time=None, int|None hold_and_release_time=None, bool|None twist_assist=None, bool|None block_to_block=None)
None async_unlock(self, **Any kwargs)
None async_set_lock_usercode(self, int code_slot, str usercode)
None async_clear_lock_usercode(self, int code_slot)
None async_lock(self, **Any kwargs)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)