Skip to content

Lock

lock

lock domain implementation.

SPEC module-attribute

SPEC: DomainSpec[Lock] = register_domain(DomainSpec(name='lock', entity_cls=Lock))

The DomainSpec registered with the shared DomainRegistry.

Lock

Bases: Entity

A Home Assistant lock entity.

Provides intent-specific actions (lock, unlock, open) and state introspection (is_locked, is_unlocked, is_locking, is_unlocking, is_jammed) rather than exposing raw lock.lock / lock.unlock service calls.

The open action is only available on lock hardware that advertises the OPEN (unlatch) feature via the supported_features attribute; on locks without it open is a no-op that logs a debug message, so user code does not break across heterogeneous lock backends. Callers can pre-check with supports_open.

Source code in src/haclient/domains/lock.py
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
class Lock(Entity):
    """A Home Assistant lock entity.

    Provides intent-specific actions (``lock``, ``unlock``, ``open``)
    and state introspection (``is_locked``, ``is_unlocked``,
    ``is_locking``, ``is_unlocking``, ``is_jammed``) rather than
    exposing raw ``lock.lock`` / ``lock.unlock`` service calls.

    The ``open`` action is only available on lock hardware that
    advertises the ``OPEN`` (unlatch) feature via the
    ``supported_features`` attribute; on locks without it ``open`` is a
    no-op that logs a debug message, so user code does not break across
    heterogeneous lock backends. Callers can pre-check with
    `supports_open`.
    """

    domain = "lock"

    # -- Listener decorators ------------------------------------------

    def on_lock(self, func: ValueChangeHandler) -> ValueChangeHandler:
        """Register a listener for when the lock becomes locked.

        Parameters
        ----------
        func : callable
            Sync or async callable invoked with ``(old_state, new_state)``
            on every transition into the ``locked`` state.

        Returns
        -------
        callable
            The same *func*, returned for decorator use.
        """
        return self._register_state_transition_listener("locked", func)

    def on_unlock(self, func: ValueChangeHandler) -> ValueChangeHandler:
        """Register a listener for when the lock becomes unlocked.

        Parameters
        ----------
        func : callable
            Sync or async callable invoked with ``(old_state, new_state)``
            on every transition into the ``unlocked`` state.

        Returns
        -------
        callable
            The same *func*, returned for decorator use.
        """
        return self._register_state_transition_listener("unlocked", func)

    def on_jam(self, func: ValueChangeHandler) -> ValueChangeHandler:
        """Register a listener for when the lock jams.

        Parameters
        ----------
        func : callable
            Sync or async callable invoked with ``(old_state, new_state)``
            on every transition into the ``jammed`` state.

        Returns
        -------
        callable
            The same *func*, returned for decorator use.
        """
        return self._register_state_transition_listener("jammed", func)

    # -- State properties ---------------------------------------------

    @property
    def is_locked(self) -> bool:
        """Whether the lock is currently locked."""
        return self.state == "locked"

    @property
    def is_unlocked(self) -> bool:
        """Whether the lock is currently unlocked."""
        return self.state == "unlocked"

    @property
    def is_locking(self) -> bool:
        """Whether the lock is currently in the process of locking."""
        return self.state == "locking"

    @property
    def is_unlocking(self) -> bool:
        """Whether the lock is currently in the process of unlocking."""
        return self.state == "unlocking"

    @property
    def is_jammed(self) -> bool:
        """Whether the lock is currently jammed."""
        return self.state == "jammed"

    @property
    def supports_open(self) -> bool:
        """Whether the underlying lock hardware supports the ``open`` action.

        Returns
        -------
        bool
            ``True`` if the entity advertises the ``OPEN`` feature in
            its ``supported_features`` bitmask, otherwise ``False``.
        """
        features = self.attributes.get("supported_features")
        if not isinstance(features, int):
            return False
        return bool(features & _FEATURE_OPEN)

    # -- Actions ------------------------------------------------------

    async def lock(self) -> None:
        """Engage the lock.

        Invokes the ``lock.lock`` Home Assistant service. No feature
        check is performed: all locks are expected to support locking.

        Raises
        ------
        CommandError
            If Home Assistant rejects the service call.
        HTTPError
            If the REST call returns a non-2xx response.
        TimeoutError
            If the call exceeds the configured request timeout.
        ConnectionClosedError
            If the WebSocket disconnects mid-call.
        """
        await self._call_service("lock")

    async def unlock(self) -> None:
        """Release the lock.

        Invokes the ``lock.unlock`` Home Assistant service. No feature
        check is performed: all locks are expected to support unlocking.

        Raises
        ------
        CommandError
            If Home Assistant rejects the service call.
        HTTPError
            If the REST call returns a non-2xx response.
        TimeoutError
            If the call exceeds the configured request timeout.
        ConnectionClosedError
            If the WebSocket disconnects mid-call.
        """
        await self._call_service("unlock")

    async def open(self) -> None:
        """Open (unlatch) the lock, if supported.

        Degrades safely: if the lock does not advertise the ``OPEN``
        feature, this method logs a debug message and returns without
        raising, so user code that targets a heterogeneous fleet of
        locks does not break on hardware that lacks an unlatch.

        Callers that need to know whether the action will actually be
        dispatched can check `supports_open` first.
        """
        if not self.supports_open:
            _LOGGER.debug(
                "open() unsupported for %s; skipping (no LockEntityFeature.OPEN)",
                self.entity_id,
            )
            return
        await self._call_service("open")

is_locked property

is_locked: bool

Whether the lock is currently locked.

is_unlocked property

is_unlocked: bool

Whether the lock is currently unlocked.

is_locking property

is_locking: bool

Whether the lock is currently in the process of locking.

is_unlocking property

is_unlocking: bool

Whether the lock is currently in the process of unlocking.

is_jammed property

is_jammed: bool

Whether the lock is currently jammed.

supports_open property

supports_open: bool

Whether the underlying lock hardware supports the open action.

Returns:

Type Description
bool

True if the entity advertises the OPEN feature in its supported_features bitmask, otherwise False.

on_lock

on_lock(func: ValueChangeHandler) -> ValueChangeHandler

Register a listener for when the lock becomes locked.

Parameters:

Name Type Description Default
func callable

Sync or async callable invoked with (old_state, new_state) on every transition into the locked state.

required

Returns:

Type Description
callable

The same func, returned for decorator use.

Source code in src/haclient/domains/lock.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def on_lock(self, func: ValueChangeHandler) -> ValueChangeHandler:
    """Register a listener for when the lock becomes locked.

    Parameters
    ----------
    func : callable
        Sync or async callable invoked with ``(old_state, new_state)``
        on every transition into the ``locked`` state.

    Returns
    -------
    callable
        The same *func*, returned for decorator use.
    """
    return self._register_state_transition_listener("locked", func)

on_unlock

on_unlock(func: ValueChangeHandler) -> ValueChangeHandler

Register a listener for when the lock becomes unlocked.

Parameters:

Name Type Description Default
func callable

Sync or async callable invoked with (old_state, new_state) on every transition into the unlocked state.

required

Returns:

Type Description
callable

The same func, returned for decorator use.

Source code in src/haclient/domains/lock.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def on_unlock(self, func: ValueChangeHandler) -> ValueChangeHandler:
    """Register a listener for when the lock becomes unlocked.

    Parameters
    ----------
    func : callable
        Sync or async callable invoked with ``(old_state, new_state)``
        on every transition into the ``unlocked`` state.

    Returns
    -------
    callable
        The same *func*, returned for decorator use.
    """
    return self._register_state_transition_listener("unlocked", func)

on_jam

on_jam(func: ValueChangeHandler) -> ValueChangeHandler

Register a listener for when the lock jams.

Parameters:

Name Type Description Default
func callable

Sync or async callable invoked with (old_state, new_state) on every transition into the jammed state.

required

Returns:

Type Description
callable

The same func, returned for decorator use.

Source code in src/haclient/domains/lock.py
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def on_jam(self, func: ValueChangeHandler) -> ValueChangeHandler:
    """Register a listener for when the lock jams.

    Parameters
    ----------
    func : callable
        Sync or async callable invoked with ``(old_state, new_state)``
        on every transition into the ``jammed`` state.

    Returns
    -------
    callable
        The same *func*, returned for decorator use.
    """
    return self._register_state_transition_listener("jammed", func)

lock async

lock() -> None

Engage the lock.

Invokes the lock.lock Home Assistant service. No feature check is performed: all locks are expected to support locking.

Raises:

Type Description
CommandError

If Home Assistant rejects the service call.

HTTPError

If the REST call returns a non-2xx response.

TimeoutError

If the call exceeds the configured request timeout.

ConnectionClosedError

If the WebSocket disconnects mid-call.

Source code in src/haclient/domains/lock.py
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
async def lock(self) -> None:
    """Engage the lock.

    Invokes the ``lock.lock`` Home Assistant service. No feature
    check is performed: all locks are expected to support locking.

    Raises
    ------
    CommandError
        If Home Assistant rejects the service call.
    HTTPError
        If the REST call returns a non-2xx response.
    TimeoutError
        If the call exceeds the configured request timeout.
    ConnectionClosedError
        If the WebSocket disconnects mid-call.
    """
    await self._call_service("lock")

unlock async

unlock() -> None

Release the lock.

Invokes the lock.unlock Home Assistant service. No feature check is performed: all locks are expected to support unlocking.

Raises:

Type Description
CommandError

If Home Assistant rejects the service call.

HTTPError

If the REST call returns a non-2xx response.

TimeoutError

If the call exceeds the configured request timeout.

ConnectionClosedError

If the WebSocket disconnects mid-call.

Source code in src/haclient/domains/lock.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
async def unlock(self) -> None:
    """Release the lock.

    Invokes the ``lock.unlock`` Home Assistant service. No feature
    check is performed: all locks are expected to support unlocking.

    Raises
    ------
    CommandError
        If Home Assistant rejects the service call.
    HTTPError
        If the REST call returns a non-2xx response.
    TimeoutError
        If the call exceeds the configured request timeout.
    ConnectionClosedError
        If the WebSocket disconnects mid-call.
    """
    await self._call_service("unlock")

open async

open() -> None

Open (unlatch) the lock, if supported.

Degrades safely: if the lock does not advertise the OPEN feature, this method logs a debug message and returns without raising, so user code that targets a heterogeneous fleet of locks does not break on hardware that lacks an unlatch.

Callers that need to know whether the action will actually be dispatched can check supports_open first.

Source code in src/haclient/domains/lock.py
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
async def open(self) -> None:
    """Open (unlatch) the lock, if supported.

    Degrades safely: if the lock does not advertise the ``OPEN``
    feature, this method logs a debug message and returns without
    raising, so user code that targets a heterogeneous fleet of
    locks does not break on hardware that lacks an unlatch.

    Callers that need to know whether the action will actually be
    dispatched can check `supports_open` first.
    """
    if not self.supports_open:
        _LOGGER.debug(
            "open() unsupported for %s; skipping (no LockEntityFeature.OPEN)",
            self.entity_id,
        )
        return
    await self._call_service("open")