Home Assistant Unofficial Reference 2024.12.1
lock.py
Go to the documentation of this file.
1 """Nuki.io lock platform."""
2 
3 from __future__ import annotations
4 
5 from abc import abstractmethod
6 from typing import Any
7 
8 from pynuki import NukiLock, NukiOpener
9 from pynuki.constants import MODE_OPENER_CONTINUOUS
10 from pynuki.device import NukiDevice
11 from requests.exceptions import RequestException
12 import voluptuous as vol
13 
14 from homeassistant.components.lock import LockEntity, LockEntityFeature
15 from homeassistant.config_entries import ConfigEntry
16 from homeassistant.core import HomeAssistant
17 from homeassistant.helpers import config_validation as cv, entity_platform
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 
20 from . import NukiEntryData
21 from .const import ATTR_ENABLE, ATTR_UNLATCH, DOMAIN as NUKI_DOMAIN, ERROR_STATES
22 from .entity import NukiEntity
23 from .helpers import CannotConnect
24 
25 
27  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
28 ) -> None:
29  """Set up the Nuki lock platform."""
30  entry_data: NukiEntryData = hass.data[NUKI_DOMAIN][entry.entry_id]
31  coordinator = entry_data.coordinator
32 
33  entities: list[NukiDeviceEntity] = [
34  NukiLockEntity(coordinator, lock) for lock in entry_data.locks
35  ]
36  entities.extend(
37  [NukiOpenerEntity(coordinator, opener) for opener in entry_data.openers]
38  )
39  async_add_entities(entities)
40 
41  platform = entity_platform.async_get_current_platform()
42  platform.async_register_entity_service(
43  "lock_n_go",
44  {
45  vol.Optional(ATTR_UNLATCH, default=False): cv.boolean,
46  },
47  "lock_n_go",
48  )
49 
50  platform.async_register_entity_service(
51  "set_continuous_mode",
52  {
53  vol.Required(ATTR_ENABLE): cv.boolean,
54  },
55  "set_continuous_mode",
56  )
57 
58 
59 class NukiDeviceEntity[_NukiDeviceT: NukiDevice](NukiEntity[_NukiDeviceT], LockEntity):
60  """Representation of a Nuki device."""
61 
62  _attr_has_entity_name = True
63  _attr_supported_features = LockEntityFeature.OPEN
64  _attr_translation_key = "nuki_lock"
65  _attr_name = None
66 
67  @property
68  def unique_id(self) -> str | None:
69  """Return a unique ID."""
70  return self._nuki_device.nuki_id
71 
72  @property
73  def available(self) -> bool:
74  """Return True if entity is available."""
75  return super().available and self._nuki_device.state not in ERROR_STATES
76 
77  @abstractmethod
78  def lock(self, **kwargs: Any) -> None:
79  """Lock the device."""
80 
81  @abstractmethod
82  def unlock(self, **kwargs: Any) -> None:
83  """Unlock the device."""
84 
85  @abstractmethod
86  def open(self, **kwargs: Any) -> None:
87  """Open the door latch."""
88 
89 
91  """Representation of a Nuki lock."""
92 
93  @property
94  def is_locked(self) -> bool:
95  """Return true if lock is locked."""
96  return self._nuki_device.is_locked
97 
98  def lock(self, **kwargs: Any) -> None:
99  """Lock the device."""
100  try:
101  self._nuki_device.lock()
102  except RequestException as err:
103  raise CannotConnect from err
104 
105  def unlock(self, **kwargs: Any) -> None:
106  """Unlock the device."""
107  try:
108  self._nuki_device.unlock()
109  except RequestException as err:
110  raise CannotConnect from err
111 
112  def open(self, **kwargs: Any) -> None:
113  """Open the door latch."""
114  try:
115  self._nuki_device.unlatch()
116  except RequestException as err:
117  raise CannotConnect from err
118 
119  def lock_n_go(self, unlatch: bool) -> None:
120  """Lock and go.
121 
122  This will first unlock the door, then wait for 20 seconds (or another
123  amount of time depending on the lock settings) and relock.
124  """
125  try:
126  self._nuki_device.lock_n_go(unlatch)
127  except RequestException as err:
128  raise CannotConnect from err
129 
130 
132  """Representation of a Nuki opener."""
133 
134  @property
135  def is_locked(self) -> bool:
136  """Return true if either ring-to-open or continuous mode is enabled."""
137  return not (
138  self._nuki_device.is_rto_activated
139  or self._nuki_device.mode == MODE_OPENER_CONTINUOUS
140  )
141 
142  def lock(self, **kwargs: Any) -> None:
143  """Disable ring-to-open."""
144  try:
145  self._nuki_device.deactivate_rto()
146  except RequestException as err:
147  raise CannotConnect from err
148 
149  def unlock(self, **kwargs: Any) -> None:
150  """Enable ring-to-open."""
151  try:
152  self._nuki_device.activate_rto()
153  except RequestException as err:
154  raise CannotConnect from err
155 
156  def open(self, **kwargs: Any) -> None:
157  """Buzz open the door."""
158  try:
159  self._nuki_device.electric_strike_actuation()
160  except RequestException as err:
161  raise CannotConnect from err
162 
163  def lock_n_go(self, unlatch: bool) -> None:
164  """Stub service."""
165 
166  def set_continuous_mode(self, enable: bool) -> None:
167  """Continuous Mode.
168 
169  This feature will cause the door to automatically open when anyone
170  rings the bell. This is similar to ring-to-open, except that it does
171  not automatically deactivate
172  """
173  try:
174  if enable:
175  self._nuki_device.activate_continuous_mode()
176  else:
177  self._nuki_device.deactivate_continuous_mode()
178  except RequestException as err:
179  raise CannotConnect from err
None set_continuous_mode(self, bool enable)
Definition: lock.py:166
None open(self, **Any kwargs)
Definition: lock.py:86
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: lock.py:28
str|None unique_id(self)
Definition: lock.py:68
None lock(self, **Any kwargs)
Definition: lock.py:78
None unlock(self, **Any kwargs)
Definition: lock.py:82