-
Notifications
You must be signed in to change notification settings - Fork 0
/
lock.py
207 lines (167 loc) · 7.04 KB
/
lock.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
from homeassistant.components.lock import LockEntity, SUPPORT_OPEN
from homeassistant.helpers import entity_platform, service
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from aionuki import NukiLock, NukiOpener
from .const import DOMAIN, SERVICE_LOCK_N_GO, ATTR_CODE
from homeassistant.helpers.config_validation import ( # https://github.com/home-assistant/core/blob/dev/homeassistant/components/lock/__init__.py
make_entity_service_schema,
)
import logging
_LOGGER = logging.getLogger(__name__)
"""
TODO: read and base on this
https://github.com/home-assistant/core/blob/2fb3be50ab0b806cfc099bc3671ad6c8ee4195e4/homeassistant/components/august/lock.py
"""
# Rename to lockentity
class NukiLockPlatform(LockEntity):
# Should Home Assistant check with the entity for an updated state. If set to False, entity will need to notify Home Assistant of new updates by calling one of the schedule update methods.
should_poll = False
lockObj = None
def __init__(self, coordinator, config, obj):
# super().__init__(coordinator)
self._config = config
self.coordinator = coordinator
self.lockObj = obj
# Generic Properties
@property
def device_class(self):
""" Indicate if Home Assistant is able to read the state and control the underlying device. """
if isinstance(self.lock, NukiLock):
return "door"
elif isinstance(self.lock, NukiOpener):
return "opener"
else:
return None
@property
def icon(self):
""" Indicate if Home Assistant is able to read the state and control the underlying device. """
return "mdi:doorbell" if (self.device_class == "opener") else None
@property
def available(self):
""" Indicate if Home Assistant is able to read the state and control the underlying device. """
return True and self.enabled
# https://developers.home-assistant.io/docs/device_registry_index
@property
def device_info(self):
"""Device info."""
return {
"identifiers": {(DOMAIN, self.lockObj.nuki_id)},
"name": self.name,
"manufacturer": "Nuki",
"model": "Nuki Smart Lock",
"default_name": "Nuki Smart Lock",
"via_device": self.coordinator.bridgeId,
}
# if self._firmware:
# device_info["sw_version"] = self._firmware
'''
@property
def state_attributes(self):
"""Return the state attributes."""
state_attr = {}
for prop, attr in PROP_TO_ATTR.items():
value = getattr(self, prop)
if value is not None:
state_attr[attr] = value
return state_attr
'''
@property
def state(self):
"""Return the state."""
locked = self.is_locked
if locked is None:
return None
return "locked" if locked else "unlocked"
@property
def supported_features(self):
"""Flag supported features."""
"""
Have to cast to int. If not, error:
File "/workspaces/homeassistant_core/homeassistant/components/lock/device_action.py", line 64, in async_get_actions
if features & (SUPPORT_OPEN):
TypeError: unsupported operand type(s) for &: 'method' and 'int'
"""
return int(SUPPORT_OPEN)
@property
def device_state_attributes(self):
""" Extra information to store in the state machine. It needs to be information that further explains the state, it should not be static information like firmware version. """
return self.lockObj._json
@property
def unique_id(self):
""" A unique identifier for this entity. Needs to be unique within a platform (ie light.hue). Should not be configurable by the user or be changeable. Learn more. """
return self.lockObj.nuki_id
@property
def name(self):
""" Name of the entity. """
return self.lockObj.name
# Lock properties
@property
def is_locked(self):
""" Indication of whether the lock is currently locked. Used to determine state. """
return self.lockObj.is_locked
@property
def is_open(self):
""" Indication of whether the lock is currently locked. Used to determine state. """
return self.lockObj.is_open
@property
def is_lockngoinprogress(self):
""" Indication of whether the lock is currently locked. Used to determine state. """
return self.lockObj.is_lockngo_in_progress
@property
def changed_by(self):
""" Describes what the last change was triggered by. """
return "callback"
@property
def code_format(self):
""" Regex for code format or None if no code is required. """
return "[0-9]+"
def testCode(self, code=None):
return code == "hello"
async def async_unlock(self, *args, code=None):
"""Unlock all or specified locks. A code to unlock the lock with may optionally be specified."""
_LOGGER.debug(f"UnlockArgs: code={code}")
if self.testCode(code):
await self.lockObj.unlock()
else:
_LOGGER.warning(f"Wrong code: code={code}")
async def async_lock(self, code=None):
"""Lock all or specified locks. A code to lock the lock with may optionally be specified."""
if self.testCode(code):
await self.lockObj.lock()
else:
_LOGGER.warning(f"Wrong code: code={code}")
async def async_open(self, code=None):
"""Open (unlatch) all or specified locks. A code to open the lock with may optionally be specified."""
if self.testCode(code):
await self.lockObj.unlatch()
else:
_LOGGER.warning(f"Wrong code: code={code}")
async def async_lockngo(self, code=None):
if self.testCode(code):
await self.lockObj.lock_n_go() # TODO: support for unlatch=False, block=False):
else:
_LOGGER.warning(f"Wrong code: code={code}")
# lock n go?
# Sepparate component for opener: no sense to keep the state of an opener. Maybe just turn on when opening and back off after 1s
async def async_setup(hass, config_entry):
LOCK_SERVICE_SCHEMA = make_entity_service_schema(
{vol.Optional(ATTR_CODE): cv.string}
)
platform = hass.data[DOMAIN][config_entry.entry_id]
platform.async_register_entity_service(
SERVICE_LOCK_N_GO, LOCK_SERVICE_SCHEMA, "async_lockngo"
)
_LOGGER.debug(f"Nuki Lock component setup finished: include service.")
# Setup
async def async_setup_entry(hass, config_entry, async_add_devices):
"""Set up the Hue lights from a config entry."""
platform = hass.data[DOMAIN][config_entry.entry_id]
deviceList = []
for lock in platform.devices:
_LOGGER.debug(f"Setting up lock: {lock}")
device = NukiLockPlatform(platform, config_entry.data, lock)
platform.registerUpdateCallback(device.async_schedule_update_ha_state)
deviceList.append(device)
platform = entity_platform.current_platform.get()
async_add_devices(deviceList)