zwave-js-server-python 0.22.0__py3-none-any.whl → 0.23.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zwave_js_server/const.py +94 -42
- zwave_js_server/exceptions.py +4 -0
- zwave_js_server/model/association.py +1 -1
- zwave_js_server/model/command_class.py +1 -0
- zwave_js_server/model/controller.py +4 -7
- zwave_js_server/model/driver.py +1 -0
- zwave_js_server/model/endpoint.py +8 -0
- zwave_js_server/model/log_config.py +2 -2
- zwave_js_server/model/node.py +62 -41
- zwave_js_server/model/notification.py +97 -10
- zwave_js_server/model/value.py +19 -9
- zwave_js_server/util/helpers.py +14 -3
- zwave_js_server/util/lock.py +1 -1
- zwave_js_server/util/node.py +165 -54
- {zwave_js_server_python-0.22.0.dist-info → zwave_js_server_python-0.23.0.dist-info}/METADATA +1 -1
- zwave_js_server_python-0.23.0.dist-info/RECORD +31 -0
- zwave_js_server_python-0.22.0.dist-info/RECORD +0 -31
- {zwave_js_server_python-0.22.0.dist-info → zwave_js_server_python-0.23.0.dist-info}/LICENSE +0 -0
- {zwave_js_server_python-0.22.0.dist-info → zwave_js_server_python-0.23.0.dist-info}/WHEEL +0 -0
- {zwave_js_server_python-0.22.0.dist-info → zwave_js_server_python-0.23.0.dist-info}/entry_points.txt +0 -0
- {zwave_js_server_python-0.22.0.dist-info → zwave_js_server_python-0.23.0.dist-info}/top_level.txt +0 -0
zwave_js_server/const.py
CHANGED
|
@@ -1,36 +1,88 @@
|
|
|
1
1
|
"""Constants for the Z-Wave JS python library."""
|
|
2
|
-
from dataclasses import dataclass
|
|
3
2
|
from enum import Enum, IntEnum
|
|
4
3
|
from typing import Dict, List
|
|
5
4
|
|
|
6
5
|
# minimal server schema version we can handle
|
|
7
|
-
MIN_SERVER_SCHEMA_VERSION =
|
|
6
|
+
MIN_SERVER_SCHEMA_VERSION = 3
|
|
8
7
|
# max server schema version we can handle (and our code is compatible with)
|
|
9
|
-
MAX_SERVER_SCHEMA_VERSION =
|
|
8
|
+
MAX_SERVER_SCHEMA_VERSION = 3
|
|
10
9
|
|
|
11
10
|
VALUE_UNKNOWN = "unknown"
|
|
12
11
|
|
|
13
12
|
|
|
14
|
-
class
|
|
13
|
+
class CommandStatus(str, Enum):
|
|
14
|
+
"""Status of a command sent to zwave-js-server."""
|
|
15
|
+
|
|
16
|
+
ACCEPTED = "accepted"
|
|
17
|
+
QUEUED = "queued"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EntryControlEventType(IntEnum):
|
|
21
|
+
"""Entry control event types."""
|
|
22
|
+
|
|
23
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/EntryControlCC.ts#L54
|
|
24
|
+
CACHING = 0
|
|
25
|
+
CACHED_KEYS = 1
|
|
26
|
+
ENTER = 2
|
|
27
|
+
DISARM_ALL = 3
|
|
28
|
+
ARM_ALL = 4
|
|
29
|
+
ARM_AWAY = 5
|
|
30
|
+
ARM_HOME = 6
|
|
31
|
+
EXIT_DELAY = 7
|
|
32
|
+
ARM1 = 8
|
|
33
|
+
ARM2 = 9
|
|
34
|
+
ARM3 = 10
|
|
35
|
+
ARM4 = 11
|
|
36
|
+
ARM5 = 12
|
|
37
|
+
ARM6 = 13
|
|
38
|
+
RFID = 14
|
|
39
|
+
BELL = 15
|
|
40
|
+
FIRE = 16
|
|
41
|
+
POLICE = 17
|
|
42
|
+
ALERT_PANIC = 18
|
|
43
|
+
ALERT_MEDICAL = 19
|
|
44
|
+
GATE_OPEN = 20
|
|
45
|
+
GATE_CLOSE = 21
|
|
46
|
+
LOCK = 22
|
|
47
|
+
UNLOCK = 23
|
|
48
|
+
TEST = 24
|
|
49
|
+
CANCEL = 25
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class EntryControlDataType(IntEnum):
|
|
53
|
+
"""Entry control data types."""
|
|
54
|
+
|
|
55
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/EntryControlCC.ts#L83
|
|
56
|
+
NONE = 0
|
|
57
|
+
RAW = 1
|
|
58
|
+
ASCII = 2
|
|
59
|
+
MD5 = 3
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ProtocolVersion(IntEnum):
|
|
63
|
+
"""Protocol version."""
|
|
64
|
+
|
|
65
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/Types.ts#L149
|
|
66
|
+
UNKNOWN = 0
|
|
67
|
+
VERSION_2_0 = 1
|
|
68
|
+
VERSION_4_2X_OR_5_0X = 2
|
|
69
|
+
VERSION_4_5X_OR_6_0X = 3
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Multiple inheritance so that LogLevel will JSON serialize properly
|
|
73
|
+
# Reference: https://stackoverflow.com/a/51976841
|
|
74
|
+
class LogLevel(str, Enum):
|
|
15
75
|
"""Enum for log levels used by node-zwave-js."""
|
|
16
76
|
|
|
17
77
|
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/log/shared.ts#L12
|
|
18
78
|
# https://github.com/winstonjs/triple-beam/blame/master/config/npm.js#L14
|
|
19
|
-
ERROR =
|
|
20
|
-
WARN =
|
|
21
|
-
INFO =
|
|
22
|
-
HTTP =
|
|
23
|
-
VERBOSE =
|
|
24
|
-
DEBUG =
|
|
25
|
-
SILLY =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@dataclass
|
|
29
|
-
class PropertyKey:
|
|
30
|
-
"""Class to represent a property key and its name."""
|
|
31
|
-
|
|
32
|
-
key: int
|
|
33
|
-
name: str
|
|
79
|
+
ERROR = "error"
|
|
80
|
+
WARN = "warn"
|
|
81
|
+
INFO = "info"
|
|
82
|
+
HTTP = "http"
|
|
83
|
+
VERBOSE = "verbose"
|
|
84
|
+
DEBUG = "debug"
|
|
85
|
+
SILLY = "silly"
|
|
34
86
|
|
|
35
87
|
|
|
36
88
|
class CommandClass(IntEnum):
|
|
@@ -253,7 +305,7 @@ class ThermostatOperatingState(IntEnum):
|
|
|
253
305
|
THIRD_STAGE_AUX_HEAT = 11
|
|
254
306
|
|
|
255
307
|
|
|
256
|
-
class ThermostatSetpointType(
|
|
308
|
+
class ThermostatSetpointType(IntEnum):
|
|
257
309
|
"""
|
|
258
310
|
Enum with all (known/used) Z-Wave Thermostat Setpoint Types.
|
|
259
311
|
|
|
@@ -261,18 +313,18 @@ class ThermostatSetpointType(Enum):
|
|
|
261
313
|
"""
|
|
262
314
|
|
|
263
315
|
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ThermostatSetpointCC.ts#L53-L66
|
|
264
|
-
NA =
|
|
265
|
-
HEATING =
|
|
266
|
-
COOLING =
|
|
267
|
-
FURNACE =
|
|
268
|
-
DRY_AIR =
|
|
269
|
-
MOIST_AIR =
|
|
270
|
-
AUTO_CHANGEOVER =
|
|
271
|
-
ENERGY_SAVE_HEATING =
|
|
272
|
-
ENERGY_SAVE_COOLING =
|
|
273
|
-
AWAY_HEATING =
|
|
274
|
-
AWAY_COOLING =
|
|
275
|
-
FULL_POWER =
|
|
316
|
+
NA = 0
|
|
317
|
+
HEATING = 1
|
|
318
|
+
COOLING = 2
|
|
319
|
+
FURNACE = 7
|
|
320
|
+
DRY_AIR = 8
|
|
321
|
+
MOIST_AIR = 9
|
|
322
|
+
AUTO_CHANGEOVER = 10
|
|
323
|
+
ENERGY_SAVE_HEATING = 11
|
|
324
|
+
ENERGY_SAVE_COOLING = 12
|
|
325
|
+
AWAY_HEATING = 13
|
|
326
|
+
AWAY_COOLING = 14
|
|
327
|
+
FULL_POWER = 15
|
|
276
328
|
|
|
277
329
|
|
|
278
330
|
# In Z-Wave the modes and presets are both in ThermostatMode.
|
|
@@ -336,16 +388,16 @@ class BarrierState(IntEnum):
|
|
|
336
388
|
OPEN = 255
|
|
337
389
|
|
|
338
390
|
|
|
339
|
-
class ColorComponent(
|
|
391
|
+
class ColorComponent(IntEnum):
|
|
340
392
|
"""Enum with all (known/used) Color Switch CC colors."""
|
|
341
393
|
|
|
342
394
|
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ColorSwitchCC.ts#L62
|
|
343
|
-
WARM_WHITE =
|
|
344
|
-
COLD_WHITE =
|
|
345
|
-
RED =
|
|
346
|
-
GREEN =
|
|
347
|
-
BLUE =
|
|
348
|
-
AMBER =
|
|
349
|
-
CYAN =
|
|
350
|
-
PURPLE =
|
|
351
|
-
INDEX =
|
|
395
|
+
WARM_WHITE = 0
|
|
396
|
+
COLD_WHITE = 1
|
|
397
|
+
RED = 2
|
|
398
|
+
GREEN = 3
|
|
399
|
+
BLUE = 4
|
|
400
|
+
AMBER = 5
|
|
401
|
+
CYAN = 6
|
|
402
|
+
PURPLE = 7
|
|
403
|
+
INDEX = 8
|
zwave_js_server/exceptions.py
CHANGED
|
@@ -82,6 +82,10 @@ class InvalidNewValue(BaseZwaveJSServerError):
|
|
|
82
82
|
"""Exception raised when target new value is invalid based on Value metadata."""
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
class ValueTypeError(BaseZwaveJSServerError):
|
|
86
|
+
"""Exception raised when target Zwave value is the wrong type."""
|
|
87
|
+
|
|
88
|
+
|
|
85
89
|
class SetValueFailed(BaseZwaveJSServerError):
|
|
86
90
|
"""
|
|
87
91
|
Exception raise when setting a value fails.
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
from typing import TYPE_CHECKING, Dict, List, Optional, TypedDict, cast
|
|
3
3
|
|
|
4
4
|
from ..event import Event, EventBase
|
|
5
|
-
from .association import
|
|
6
|
-
AssociationGroup,
|
|
7
|
-
Association,
|
|
8
|
-
)
|
|
5
|
+
from .association import Association, AssociationGroup
|
|
9
6
|
from .node import Node
|
|
10
7
|
|
|
11
8
|
if TYPE_CHECKING:
|
|
@@ -318,11 +315,11 @@ class Controller(EventBase):
|
|
|
318
315
|
}
|
|
319
316
|
)
|
|
320
317
|
|
|
321
|
-
async def
|
|
322
|
-
"""Send
|
|
318
|
+
async def async_remove_node_from_all_associations(self, node_id: int) -> None:
|
|
319
|
+
"""Send removeNodeFromAllAssociations command to Controller."""
|
|
323
320
|
await self.client.async_send_command(
|
|
324
321
|
{
|
|
325
|
-
"command": "controller.
|
|
322
|
+
"command": "controller.remove_node_from_all_associations",
|
|
326
323
|
"nodeId": node_id,
|
|
327
324
|
}
|
|
328
325
|
)
|
zwave_js_server/model/driver.py
CHANGED
|
@@ -6,12 +6,15 @@ https://zwave-js.github.io/node-zwave-js/#/api/endpoint?id=endpoint-properties
|
|
|
6
6
|
|
|
7
7
|
from typing import Optional, TypedDict
|
|
8
8
|
|
|
9
|
+
from .device_class import DeviceClass, DeviceClassDataType
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
class EndpointDataType(TypedDict, total=False):
|
|
11
13
|
"""Represent an endpoint data dict type."""
|
|
12
14
|
|
|
13
15
|
nodeId: int # required
|
|
14
16
|
index: int # required
|
|
17
|
+
deviceClass: DeviceClassDataType # required
|
|
15
18
|
installerIcon: int
|
|
16
19
|
userIcon: int
|
|
17
20
|
|
|
@@ -33,6 +36,11 @@ class Endpoint:
|
|
|
33
36
|
"""Return index property."""
|
|
34
37
|
return self.data["index"]
|
|
35
38
|
|
|
39
|
+
@property
|
|
40
|
+
def device_class(self) -> DeviceClass:
|
|
41
|
+
"""Return the device_class."""
|
|
42
|
+
return DeviceClass(self.data["deviceClass"])
|
|
43
|
+
|
|
36
44
|
@property
|
|
37
45
|
def installer_icon(self) -> Optional[int]:
|
|
38
46
|
"""Return installer icon property."""
|
|
@@ -31,7 +31,7 @@ class LogConfig:
|
|
|
31
31
|
"""Return LogConfigDataType dict from self."""
|
|
32
32
|
data = {
|
|
33
33
|
"enabled": self.enabled,
|
|
34
|
-
"level": self.level,
|
|
34
|
+
"level": self.level.value if self.level else None,
|
|
35
35
|
"logToFile": self.log_to_file,
|
|
36
36
|
"filename": self.filename,
|
|
37
37
|
"forceConsole": self.force_console,
|
|
@@ -43,7 +43,7 @@ class LogConfig:
|
|
|
43
43
|
"""Return LogConfig from LogConfigDataType dict."""
|
|
44
44
|
return LogConfig(
|
|
45
45
|
data.get("enabled"),
|
|
46
|
-
data
|
|
46
|
+
LogLevel(data["level"]) if "level" in data else None,
|
|
47
47
|
data.get("logToFile"),
|
|
48
48
|
data.get("filename"),
|
|
49
49
|
data.get("forceConsole"),
|
zwave_js_server/model/node.py
CHANGED
|
@@ -10,7 +10,12 @@ from .command_class import CommandClassInfo, CommandClassInfoDataType
|
|
|
10
10
|
from .device_class import DeviceClass, DeviceClassDataType
|
|
11
11
|
from .device_config import DeviceConfig, DeviceConfigDataType
|
|
12
12
|
from .endpoint import Endpoint, EndpointDataType
|
|
13
|
-
from .notification import
|
|
13
|
+
from .notification import (
|
|
14
|
+
EntryControlNotification,
|
|
15
|
+
EntryControlNotificationDataType,
|
|
16
|
+
NotificationNotification,
|
|
17
|
+
NotificationNotificationDataType,
|
|
18
|
+
)
|
|
14
19
|
from .value import (
|
|
15
20
|
ConfigurationValue,
|
|
16
21
|
MetaDataType,
|
|
@@ -19,6 +24,7 @@ from .value import (
|
|
|
19
24
|
ValueMetadata,
|
|
20
25
|
ValueNotification,
|
|
21
26
|
_get_value_id_from_dict,
|
|
27
|
+
_init_value,
|
|
22
28
|
)
|
|
23
29
|
|
|
24
30
|
if TYPE_CHECKING:
|
|
@@ -47,15 +53,17 @@ class NodeDataType(TypedDict, total=False):
|
|
|
47
53
|
status: int # 0-4 # required
|
|
48
54
|
deviceClass: DeviceClassDataType
|
|
49
55
|
zwavePlusVersion: int
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
zwavePlusNodeType: int
|
|
57
|
+
zwavePlusRoleType: int
|
|
52
58
|
isListening: bool
|
|
53
|
-
isFrequentListening: bool
|
|
59
|
+
isFrequentListening: Union[bool, str]
|
|
54
60
|
isRouting: bool
|
|
55
|
-
|
|
61
|
+
maxDataRate: int
|
|
62
|
+
supportedDataRates: List[int]
|
|
56
63
|
isSecure: bool
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
supportsBeaming: bool
|
|
65
|
+
supportsSecurity: bool
|
|
66
|
+
protocolVersion: int
|
|
59
67
|
firmwareVersion: str
|
|
60
68
|
manufacturerId: int
|
|
61
69
|
productId: int
|
|
@@ -91,10 +99,7 @@ class Node(EventBase):
|
|
|
91
99
|
for val in data["values"]:
|
|
92
100
|
value_id = _get_value_id_from_dict(self, val)
|
|
93
101
|
try:
|
|
94
|
-
|
|
95
|
-
self.values[value_id] = ConfigurationValue(self, val)
|
|
96
|
-
else:
|
|
97
|
-
self.values[value_id] = Value(self, val)
|
|
102
|
+
self.values[value_id] = _init_value(self, val)
|
|
98
103
|
except UnparseableValue:
|
|
99
104
|
# If we can't parse the value, don't store it
|
|
100
105
|
pass
|
|
@@ -156,9 +161,9 @@ class Node(EventBase):
|
|
|
156
161
|
return self.data.get("isListening")
|
|
157
162
|
|
|
158
163
|
@property
|
|
159
|
-
def is_frequent_listening(self) -> Optional[bool]:
|
|
164
|
+
def is_frequent_listening(self) -> Optional[Union[bool, str]]:
|
|
160
165
|
"""Return the is_frequent_listening."""
|
|
161
|
-
return self.data
|
|
166
|
+
return self.data.get("isFrequentListening")
|
|
162
167
|
|
|
163
168
|
@property
|
|
164
169
|
def is_routing(self) -> Optional[bool]:
|
|
@@ -166,9 +171,14 @@ class Node(EventBase):
|
|
|
166
171
|
return self.data.get("isRouting")
|
|
167
172
|
|
|
168
173
|
@property
|
|
169
|
-
def
|
|
170
|
-
"""Return the
|
|
171
|
-
return self.data.get("
|
|
174
|
+
def max_data_rate(self) -> Optional[int]:
|
|
175
|
+
"""Return the max_data_rate."""
|
|
176
|
+
return self.data.get("maxDataRate")
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def supported_data_rates(self) -> List[int]:
|
|
180
|
+
"""Return the supported_data_rates."""
|
|
181
|
+
return self.data.get("supportedDataRates", [])
|
|
172
182
|
|
|
173
183
|
@property
|
|
174
184
|
def is_secure(self) -> Optional[bool]:
|
|
@@ -176,14 +186,19 @@ class Node(EventBase):
|
|
|
176
186
|
return self.data.get("isSecure")
|
|
177
187
|
|
|
178
188
|
@property
|
|
179
|
-
def
|
|
180
|
-
"""Return the
|
|
181
|
-
return self.data.get("
|
|
189
|
+
def protocol_version(self) -> Optional[int]:
|
|
190
|
+
"""Return the protocol_version."""
|
|
191
|
+
return self.data.get("protocolVersion")
|
|
182
192
|
|
|
183
193
|
@property
|
|
184
|
-
def
|
|
185
|
-
"""Return the
|
|
186
|
-
return self.data.get("
|
|
194
|
+
def supports_beaming(self) -> Optional[bool]:
|
|
195
|
+
"""Return the supports_beaming."""
|
|
196
|
+
return self.data.get("supportsBeaming")
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def supports_security(self) -> Optional[bool]:
|
|
200
|
+
"""Return the supports_security."""
|
|
201
|
+
return self.data.get("supportsSecurity")
|
|
187
202
|
|
|
188
203
|
@property
|
|
189
204
|
def manufacturer_id(self) -> Optional[int]:
|
|
@@ -211,14 +226,14 @@ class Node(EventBase):
|
|
|
211
226
|
return self.data.get("zwavePlusVersion")
|
|
212
227
|
|
|
213
228
|
@property
|
|
214
|
-
def
|
|
215
|
-
"""Return the
|
|
216
|
-
return self.data.get("
|
|
229
|
+
def zwave_plus_node_type(self) -> Optional[int]:
|
|
230
|
+
"""Return the zwave_plus_node_type."""
|
|
231
|
+
return self.data.get("zwavePlusNodeType")
|
|
217
232
|
|
|
218
233
|
@property
|
|
219
|
-
def
|
|
220
|
-
"""Return the
|
|
221
|
-
return self.data.get("
|
|
234
|
+
def zwave_plus_role_type(self) -> Optional[int]:
|
|
235
|
+
"""Return the zwave_plus_role_type."""
|
|
236
|
+
return self.data.get("zwavePlusRoleType")
|
|
222
237
|
|
|
223
238
|
@property
|
|
224
239
|
def name(self) -> Optional[str]:
|
|
@@ -310,7 +325,7 @@ class Node(EventBase):
|
|
|
310
325
|
|
|
311
326
|
self.emit(event.type, event.data)
|
|
312
327
|
|
|
313
|
-
async def
|
|
328
|
+
async def async_send_command(
|
|
314
329
|
self,
|
|
315
330
|
cmd: str,
|
|
316
331
|
require_schema: Optional[int] = None,
|
|
@@ -352,7 +367,7 @@ class Node(EventBase):
|
|
|
352
367
|
raise UnwriteableValue
|
|
353
368
|
|
|
354
369
|
# the value object needs to be send to the server
|
|
355
|
-
result = await self.
|
|
370
|
+
result = await self.async_send_command(
|
|
356
371
|
"set_value",
|
|
357
372
|
valueId=val.data,
|
|
358
373
|
value=new_value,
|
|
@@ -366,11 +381,11 @@ class Node(EventBase):
|
|
|
366
381
|
|
|
367
382
|
async def async_refresh_info(self) -> None:
|
|
368
383
|
"""Send refreshInfo command to Node."""
|
|
369
|
-
await self.
|
|
384
|
+
await self.async_send_command("refresh_info", wait_for_result=False)
|
|
370
385
|
|
|
371
386
|
async def async_get_defined_value_ids(self) -> List[Value]:
|
|
372
387
|
"""Send getDefinedValueIDs command to Node."""
|
|
373
|
-
data = await self.
|
|
388
|
+
data = await self.async_send_command(
|
|
374
389
|
"get_defined_value_ids", wait_for_result=True
|
|
375
390
|
)
|
|
376
391
|
|
|
@@ -378,7 +393,8 @@ class Node(EventBase):
|
|
|
378
393
|
# We should never reach this code
|
|
379
394
|
raise FailedCommand("Command failed", "failed_command")
|
|
380
395
|
return [
|
|
381
|
-
|
|
396
|
+
_init_value(self, cast(ValueDataType, value_id))
|
|
397
|
+
for value_id in data["valueIds"]
|
|
382
398
|
]
|
|
383
399
|
|
|
384
400
|
async def async_get_value_metadata(self, val: Union[Value, str]) -> ValueMetadata:
|
|
@@ -387,21 +403,21 @@ class Node(EventBase):
|
|
|
387
403
|
if not isinstance(val, Value):
|
|
388
404
|
val = self.values[val]
|
|
389
405
|
# the value object needs to be send to the server
|
|
390
|
-
data = await self.
|
|
406
|
+
data = await self.async_send_command(
|
|
391
407
|
"get_value_metadata", valueId=val.data, wait_for_result=True
|
|
392
408
|
)
|
|
393
409
|
return ValueMetadata(cast(MetaDataType, data))
|
|
394
410
|
|
|
395
411
|
async def async_abort_firmware_update(self) -> None:
|
|
396
412
|
"""Send abortFirmwareUpdate command to Node."""
|
|
397
|
-
await self.
|
|
413
|
+
await self.async_send_command("abort_firmware_update", wait_for_result=False)
|
|
398
414
|
|
|
399
415
|
async def async_poll_value(self, val: Union[Value, str]) -> None:
|
|
400
416
|
"""Send pollValue command to Node for given value (or value_id)."""
|
|
401
417
|
# a value may be specified as value_id or the value itself
|
|
402
418
|
if not isinstance(val, Value):
|
|
403
419
|
val = self.values[val]
|
|
404
|
-
await self.
|
|
420
|
+
await self.async_send_command("poll_value", valueId=val.data, require_schema=1)
|
|
405
421
|
|
|
406
422
|
def handle_wake_up(self, event: Event) -> None:
|
|
407
423
|
"""Process a node wake up event."""
|
|
@@ -438,13 +454,13 @@ class Node(EventBase):
|
|
|
438
454
|
value_id = _get_value_id_from_dict(self, value_state)
|
|
439
455
|
value = self.values.get(value_id)
|
|
440
456
|
if value is None:
|
|
441
|
-
self.values[value_id] =
|
|
457
|
+
self.values[value_id] = _init_value(self, value_state)
|
|
442
458
|
else:
|
|
443
459
|
value.update(value_state)
|
|
444
460
|
|
|
445
461
|
def handle_value_added(self, event: Event) -> None:
|
|
446
462
|
"""Process a node value added event."""
|
|
447
|
-
value =
|
|
463
|
+
value = _init_value(self, event.data["args"])
|
|
448
464
|
self.values[value.value_id] = event.data["value"] = value
|
|
449
465
|
|
|
450
466
|
def handle_value_updated(self, event: Event) -> None:
|
|
@@ -485,9 +501,14 @@ class Node(EventBase):
|
|
|
485
501
|
|
|
486
502
|
def handle_notification(self, event: Event) -> None:
|
|
487
503
|
"""Process a node notification event."""
|
|
488
|
-
event.data["
|
|
489
|
-
|
|
490
|
-
|
|
504
|
+
if event.data["ccId"] == CommandClass.NOTIFICATION.value:
|
|
505
|
+
event.data["notification"] = NotificationNotification(
|
|
506
|
+
self, cast(NotificationNotificationDataType, event.data)
|
|
507
|
+
)
|
|
508
|
+
else:
|
|
509
|
+
event.data["notification"] = EntryControlNotification(
|
|
510
|
+
self, cast(EntryControlNotificationDataType, event.data)
|
|
511
|
+
)
|
|
491
512
|
|
|
492
513
|
def handle_firmware_update_progress(self, event: Event) -> None:
|
|
493
514
|
"""Process a node firmware update progress event."""
|
|
@@ -4,26 +4,57 @@ Model for a Zwave Node's Notification Event.
|
|
|
4
4
|
https://zwave-js.github.io/node-zwave-js/#/api/node?id=quotnotificationquot
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from typing import
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, TypedDict, Union
|
|
8
|
+
|
|
9
|
+
from zwave_js_server.util.helpers import parse_buffer
|
|
8
10
|
|
|
9
11
|
if TYPE_CHECKING:
|
|
10
12
|
from .node import Node
|
|
11
13
|
|
|
12
14
|
|
|
13
|
-
class NotificationDataType(TypedDict
|
|
14
|
-
"""Represent a notification event data dict type."""
|
|
15
|
+
class NotificationDataType(TypedDict):
|
|
16
|
+
"""Represent a generic notification event data dict type."""
|
|
15
17
|
|
|
16
18
|
source: Literal["node"] # required
|
|
17
19
|
event: Literal["notification"] # required
|
|
18
20
|
nodeId: int # required
|
|
19
|
-
|
|
21
|
+
ccId: int # required
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class EntryControlNotificationArgsDataType(TypedDict, total=False):
|
|
25
|
+
"""Represent args for a Entry Control CC notification event data dict type."""
|
|
26
|
+
|
|
27
|
+
eventType: int # required
|
|
28
|
+
dataType: int # required
|
|
29
|
+
eventData: Union[str, Dict[str, Any]]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class EntryControlNotificationDataType(NotificationDataType):
|
|
33
|
+
"""Represent an Entry Control CC notification event data dict type."""
|
|
34
|
+
|
|
35
|
+
args: EntryControlNotificationArgsDataType # required
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class NotificationNotificationArgsDataType(TypedDict, total=False):
|
|
39
|
+
"""Represent args for a Notification CC notification event data dict type."""
|
|
40
|
+
|
|
41
|
+
type: int # required
|
|
42
|
+
label: str # required
|
|
43
|
+
event: int # required
|
|
44
|
+
eventLabel: str # required
|
|
20
45
|
parameters: Dict[str, Any]
|
|
21
46
|
|
|
22
47
|
|
|
23
|
-
class
|
|
24
|
-
"""
|
|
48
|
+
class NotificationNotificationDataType(NotificationDataType):
|
|
49
|
+
"""Represent a Notification CC notification event data dict type."""
|
|
25
50
|
|
|
26
|
-
|
|
51
|
+
args: NotificationNotificationArgsDataType # required
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class NotificationNotification:
|
|
55
|
+
"""Model for a Zwave Node's Notification CC notification event."""
|
|
56
|
+
|
|
57
|
+
def __init__(self, node: "Node", data: NotificationNotificationDataType) -> None:
|
|
27
58
|
"""Initialize."""
|
|
28
59
|
self.node = node
|
|
29
60
|
self.data = data
|
|
@@ -34,11 +65,67 @@ class Notification:
|
|
|
34
65
|
return self.data["nodeId"]
|
|
35
66
|
|
|
36
67
|
@property
|
|
37
|
-
def
|
|
68
|
+
def command_class(self) -> int:
|
|
69
|
+
"""Return command class."""
|
|
70
|
+
return self.data["ccId"]
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def type_(self) -> int:
|
|
74
|
+
"""Return type property."""
|
|
75
|
+
return self.data["args"]["type"]
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def label(self) -> str:
|
|
79
|
+
"""Return label property."""
|
|
80
|
+
return self.data["args"]["label"]
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def event(self) -> int:
|
|
84
|
+
"""Return event property."""
|
|
85
|
+
return self.data["args"]["event"]
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def event_label(self) -> str:
|
|
38
89
|
"""Return notification label property."""
|
|
39
|
-
return self.data["
|
|
90
|
+
return self.data["args"]["eventLabel"]
|
|
40
91
|
|
|
41
92
|
@property
|
|
42
93
|
def parameters(self) -> Dict[str, Any]:
|
|
43
94
|
"""Return installer icon property."""
|
|
44
|
-
return self.data.get("parameters", {})
|
|
95
|
+
return self.data["args"].get("parameters", {})
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class EntryControlNotification:
|
|
99
|
+
"""Model for a Zwave Node's Entry Control CC notification event."""
|
|
100
|
+
|
|
101
|
+
def __init__(self, node: "Node", data: EntryControlNotificationDataType) -> None:
|
|
102
|
+
"""Initialize."""
|
|
103
|
+
self.node = node
|
|
104
|
+
self.data = data
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def node_id(self) -> int:
|
|
108
|
+
"""Return node ID property."""
|
|
109
|
+
return self.data["nodeId"]
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def command_class(self) -> int:
|
|
113
|
+
"""Return command class."""
|
|
114
|
+
return self.data["ccId"]
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def event_type(self) -> int:
|
|
118
|
+
"""Return event type property."""
|
|
119
|
+
return self.data["args"]["eventType"]
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def data_type(self) -> int:
|
|
123
|
+
"""Return data type property."""
|
|
124
|
+
return self.data["args"]["dataType"]
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def event_data(self) -> Optional[str]:
|
|
128
|
+
"""Return event data property."""
|
|
129
|
+
if event_data := self.data["args"].get("eventData"):
|
|
130
|
+
return parse_buffer(event_data)
|
|
131
|
+
return None
|
zwave_js_server/model/value.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""Provide a model for the Z-Wave JS value."""
|
|
2
2
|
from typing import TYPE_CHECKING, Any, Dict, Optional, TypedDict, Union
|
|
3
3
|
|
|
4
|
-
from ..const import VALUE_UNKNOWN, ConfigurationValueType
|
|
4
|
+
from ..const import VALUE_UNKNOWN, CommandClass, ConfigurationValueType
|
|
5
5
|
from ..event import Event
|
|
6
|
-
from ..util.helpers import
|
|
6
|
+
from ..util.helpers import parse_buffer
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
9
|
from .node import Node
|
|
@@ -23,6 +23,7 @@ class MetaDataType(TypedDict, total=False):
|
|
|
23
23
|
states: Dict[int, str]
|
|
24
24
|
ccSpecific: Dict[str, Any]
|
|
25
25
|
allowManualEntry: bool
|
|
26
|
+
valueSize: int
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class ValueDataType(TypedDict, total=False):
|
|
@@ -42,6 +43,15 @@ class ValueDataType(TypedDict, total=False):
|
|
|
42
43
|
ccVersion: int
|
|
43
44
|
|
|
44
45
|
|
|
46
|
+
def _init_value(
|
|
47
|
+
node: "Node", val: ValueDataType
|
|
48
|
+
) -> Union["Value", "ConfigurationValue"]:
|
|
49
|
+
"""Intialize a Value object from ValueDataType."""
|
|
50
|
+
if val["commandClass"] == CommandClass.CONFIGURATION:
|
|
51
|
+
return ConfigurationValue(node, val)
|
|
52
|
+
return Value(node, val)
|
|
53
|
+
|
|
54
|
+
|
|
45
55
|
def _get_value_id_from_dict(node: "Node", val: ValueDataType) -> str:
|
|
46
56
|
"""Return ID of value from ValueDataType dict."""
|
|
47
57
|
return get_value_id(
|
|
@@ -132,6 +142,11 @@ class ValueMetadata:
|
|
|
132
142
|
"""Return allowManualEntry."""
|
|
133
143
|
return self.data.get("allowManualEntry")
|
|
134
144
|
|
|
145
|
+
@property
|
|
146
|
+
def value_size(self) -> Optional[int]:
|
|
147
|
+
"""Return valueSize."""
|
|
148
|
+
return self.data.get("valueSize")
|
|
149
|
+
|
|
135
150
|
def update(self, data: MetaDataType) -> None:
|
|
136
151
|
"""Update data."""
|
|
137
152
|
self.data.update(data)
|
|
@@ -240,13 +255,8 @@ class Value:
|
|
|
240
255
|
self._metadata.update(data["metadata"])
|
|
241
256
|
|
|
242
257
|
# Handle buffer dict and json string in value.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if self.metadata.type in ("string", "buffer"):
|
|
246
|
-
if isinstance(self._value, dict):
|
|
247
|
-
self._value = parse_buffer(self._value)
|
|
248
|
-
elif is_json_string(self._value):
|
|
249
|
-
self._value = parse_buffer_from_json(self._value)
|
|
258
|
+
if self.metadata.type == "buffer":
|
|
259
|
+
self._value = parse_buffer(self._value)
|
|
250
260
|
|
|
251
261
|
|
|
252
262
|
class ValueNotification(Value):
|
zwave_js_server/util/helpers.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Generic Utility helper functions."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
from typing import Any, Dict
|
|
4
|
+
from typing import Any, Dict, Union
|
|
5
5
|
|
|
6
6
|
from ..exceptions import UnparseableValue
|
|
7
7
|
|
|
@@ -12,7 +12,18 @@ def is_json_string(value: Any) -> bool:
|
|
|
12
12
|
return isinstance(value, str) and value.startswith("{") and value.endswith("}")
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
def parse_buffer(value: Dict[str, Any]) -> str:
|
|
15
|
+
def parse_buffer(value: Union[Dict[str, Any], str]) -> str:
|
|
16
|
+
"""Parse value from a buffer data type."""
|
|
17
|
+
if isinstance(value, dict):
|
|
18
|
+
return parse_buffer_from_dict(value)
|
|
19
|
+
|
|
20
|
+
if is_json_string(value):
|
|
21
|
+
return parse_buffer_from_json(value)
|
|
22
|
+
|
|
23
|
+
return value
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def parse_buffer_from_dict(value: Dict[str, Any]) -> str:
|
|
16
27
|
"""Parse value dictionary from a buffer data type."""
|
|
17
28
|
if value.get("type") != "Buffer" or "data" not in value:
|
|
18
29
|
raise UnparseableValue(f"Unparseable value: {value}") from ValueError(
|
|
@@ -24,6 +35,6 @@ def parse_buffer(value: Dict[str, Any]) -> str:
|
|
|
24
35
|
def parse_buffer_from_json(value: str) -> str:
|
|
25
36
|
"""Parse value string from a buffer data type."""
|
|
26
37
|
try:
|
|
27
|
-
return
|
|
38
|
+
return parse_buffer_from_dict(json.loads(value))
|
|
28
39
|
except ValueError as err:
|
|
29
40
|
raise UnparseableValue(f"Unparseable value: {value}") from err
|
zwave_js_server/util/lock.py
CHANGED
|
@@ -13,7 +13,7 @@ from ..const import (
|
|
|
13
13
|
)
|
|
14
14
|
from ..exceptions import NotFoundError
|
|
15
15
|
from ..model.node import Node
|
|
16
|
-
from ..model.value import
|
|
16
|
+
from ..model.value import Value, get_value_id
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def get_code_slot_value(node: Node, code_slot: int, property_name: str) -> Value:
|
zwave_js_server/util/node.py
CHANGED
|
@@ -1,58 +1,17 @@
|
|
|
1
1
|
"""Utility functions for Z-Wave JS nodes."""
|
|
2
2
|
import json
|
|
3
|
-
from typing import Optional, Union
|
|
3
|
+
from typing import Dict, Optional, Tuple, Union, cast
|
|
4
4
|
|
|
5
|
-
from ..const import CommandClass, ConfigurationValueType
|
|
6
|
-
from ..exceptions import InvalidNewValue, NotFoundError, SetValueFailed
|
|
5
|
+
from ..const import CommandClass, CommandStatus, ConfigurationValueType
|
|
6
|
+
from ..exceptions import InvalidNewValue, NotFoundError, SetValueFailed, ValueTypeError
|
|
7
7
|
from ..model.node import Node
|
|
8
8
|
from ..model.value import ConfigurationValue, get_value_id
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
property_key: Optional[Union[int, str]] = None,
|
|
16
|
-
) -> ConfigurationValue:
|
|
17
|
-
"""
|
|
18
|
-
Set a value for a config parameter on this node.
|
|
19
|
-
|
|
20
|
-
new_value and property_ can be provided as labels, so we need to resolve them to
|
|
21
|
-
the appropriate key
|
|
22
|
-
"""
|
|
23
|
-
config_values = node.get_configuration_values()
|
|
24
|
-
|
|
25
|
-
# If a property name is provided, we have to search for the correct value since
|
|
26
|
-
# we can't use value ID
|
|
27
|
-
if isinstance(property_or_property_name, str):
|
|
28
|
-
try:
|
|
29
|
-
zwave_value = next(
|
|
30
|
-
config_value
|
|
31
|
-
for config_value in config_values.values()
|
|
32
|
-
if config_value.property_name == property_or_property_name
|
|
33
|
-
)
|
|
34
|
-
except StopIteration:
|
|
35
|
-
raise NotFoundError(
|
|
36
|
-
"Configuration parameter with parameter name "
|
|
37
|
-
f"{property_or_property_name} could not be found"
|
|
38
|
-
) from None
|
|
39
|
-
else:
|
|
40
|
-
value_id = get_value_id(
|
|
41
|
-
node,
|
|
42
|
-
CommandClass.CONFIGURATION,
|
|
43
|
-
property_or_property_name,
|
|
44
|
-
endpoint=0,
|
|
45
|
-
property_key=property_key,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
try:
|
|
49
|
-
zwave_value = config_values[value_id]
|
|
50
|
-
except KeyError:
|
|
51
|
-
raise NotFoundError(
|
|
52
|
-
f"Configuration parameter with value ID {value_id} could not be "
|
|
53
|
-
"found"
|
|
54
|
-
) from None
|
|
55
|
-
|
|
11
|
+
def _validate_and_transform_new_value(
|
|
12
|
+
zwave_value: ConfigurationValue, new_value: Union[int, str]
|
|
13
|
+
) -> int:
|
|
14
|
+
"""Validate a new value and return the integer value to set."""
|
|
56
15
|
# Validate that new value for enumerated configuration parameter is a valid state
|
|
57
16
|
# key or label
|
|
58
17
|
if (
|
|
@@ -64,8 +23,8 @@ async def async_set_config_parameter(
|
|
|
64
23
|
]
|
|
65
24
|
):
|
|
66
25
|
raise InvalidNewValue(
|
|
67
|
-
"Must provide a value that represents a valid
|
|
68
|
-
f"{json.dumps(zwave_value.metadata.states)}"
|
|
26
|
+
f"Must provide a value for {zwave_value.value_id} that represents a valid "
|
|
27
|
+
f"state key or label from {json.dumps(zwave_value.metadata.states)}"
|
|
69
28
|
)
|
|
70
29
|
|
|
71
30
|
# Validate that new value for manual entry configuration parameter is a valid state
|
|
@@ -76,8 +35,8 @@ async def async_set_config_parameter(
|
|
|
76
35
|
and str(new_value) not in zwave_value.metadata.states.values()
|
|
77
36
|
):
|
|
78
37
|
raise InvalidNewValue(
|
|
79
|
-
"Must provide a value that represents a valid
|
|
80
|
-
f"{list(zwave_value.metadata.states.values())}"
|
|
38
|
+
f"Must provide a value for {zwave_value.value_id} that represents a valid "
|
|
39
|
+
f"state from {list(zwave_value.metadata.states.values())}"
|
|
81
40
|
)
|
|
82
41
|
|
|
83
42
|
# If needed, convert a state label to its key. We know the state exists because
|
|
@@ -115,12 +74,164 @@ async def async_set_config_parameter(
|
|
|
115
74
|
f"Must provide a value within the target range ({', '.join(bounds)})"
|
|
116
75
|
)
|
|
117
76
|
|
|
77
|
+
return new_value
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def partial_param_bit_shift(property_key: int) -> int:
|
|
81
|
+
"""Get the number of bits to shift the value for a given property key."""
|
|
82
|
+
# We can get the binary representation of the property key, reverse it,
|
|
83
|
+
# and find the first 1
|
|
84
|
+
return bin(property_key)[::-1].index("1")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async def async_bulk_set_partial_config_parameters(
|
|
88
|
+
node: Node,
|
|
89
|
+
property_: int,
|
|
90
|
+
new_value: Union[int, Dict[int, Union[int, str]]],
|
|
91
|
+
) -> CommandStatus:
|
|
92
|
+
"""Bulk set partial configuration values on this node."""
|
|
93
|
+
config_values = node.get_configuration_values()
|
|
94
|
+
property_values = [
|
|
95
|
+
value for value in config_values.values() if value.property_ == property_
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
# If we can't find any values with this property, the property is wrong
|
|
99
|
+
if not property_values:
|
|
100
|
+
raise NotFoundError(
|
|
101
|
+
f"Configuration parameter {property_} for node {node.node_id} not found"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# If we only find one value with this property_, we know this value isn't split
|
|
105
|
+
# into partial params
|
|
106
|
+
if len(property_values) == 1:
|
|
107
|
+
raise ValueTypeError(
|
|
108
|
+
f"Configuration parameter {property_} for node {node.node_id} does not "
|
|
109
|
+
"have partials"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# If new_value is a dictionary, we need to calculate the full value to send
|
|
113
|
+
if isinstance(new_value, dict):
|
|
114
|
+
temp_value = 0
|
|
115
|
+
# For each property key provided, we bit shift the partial value using the
|
|
116
|
+
# property_key
|
|
117
|
+
for property_key, partial_value in new_value.items():
|
|
118
|
+
value_id = get_value_id(
|
|
119
|
+
node, CommandClass.CONFIGURATION, property_, property_key=property_key
|
|
120
|
+
)
|
|
121
|
+
if value_id not in node.values:
|
|
122
|
+
raise NotFoundError(
|
|
123
|
+
f"Bitmask {property_key} ({hex(property_key)}) not found for "
|
|
124
|
+
f"parameter {property_}"
|
|
125
|
+
)
|
|
126
|
+
zwave_value = cast(ConfigurationValue, node.values[value_id])
|
|
127
|
+
partial_value = _validate_and_transform_new_value(
|
|
128
|
+
zwave_value, partial_value
|
|
129
|
+
)
|
|
130
|
+
temp_value += partial_value << partial_param_bit_shift(property_key)
|
|
131
|
+
|
|
132
|
+
# To set partial parameters in bulk, we also have to include cached values for
|
|
133
|
+
# property keys that haven't been specified
|
|
134
|
+
for property_value in property_values:
|
|
135
|
+
if property_value.property_key not in new_value:
|
|
136
|
+
temp_value += cast(
|
|
137
|
+
int, property_value.value
|
|
138
|
+
) << partial_param_bit_shift(cast(int, property_value.property_key))
|
|
139
|
+
|
|
140
|
+
new_value = temp_value
|
|
141
|
+
else:
|
|
142
|
+
remaining_value = new_value
|
|
143
|
+
|
|
144
|
+
# Break down the bulk value into partial values and validate them against
|
|
145
|
+
# each partial parameter's metadata by looping through the property values
|
|
146
|
+
# starting with the highest property key
|
|
147
|
+
for zwave_value in sorted(
|
|
148
|
+
property_values, key=lambda val: cast(int, val.property_key), reverse=True
|
|
149
|
+
):
|
|
150
|
+
property_key = cast(int, zwave_value.property_key)
|
|
151
|
+
multiplication_factor = 2 ** partial_param_bit_shift(property_key)
|
|
152
|
+
partial_value = int(remaining_value / multiplication_factor)
|
|
153
|
+
remaining_value = remaining_value % multiplication_factor
|
|
154
|
+
_validate_and_transform_new_value(zwave_value, partial_value)
|
|
155
|
+
|
|
156
|
+
cmd_response = await node.async_send_command(
|
|
157
|
+
"set_value",
|
|
158
|
+
valueId={
|
|
159
|
+
"commandClass": CommandClass.CONFIGURATION.value,
|
|
160
|
+
"property": property_,
|
|
161
|
+
},
|
|
162
|
+
value=new_value,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# If we didn't wait for a response, we assume the command has been queued
|
|
166
|
+
if cmd_response is None:
|
|
167
|
+
return CommandStatus.QUEUED
|
|
168
|
+
|
|
169
|
+
if not cast(bool, cmd_response["success"]):
|
|
170
|
+
raise SetValueFailed(
|
|
171
|
+
"Unable to set value, refer to "
|
|
172
|
+
"https://zwave-js.github.io/node-zwave-js/#/api/node?id=setvalue for "
|
|
173
|
+
"possible reasons"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# If we received a response that is not false, the command was successful
|
|
177
|
+
return CommandStatus.ACCEPTED
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
async def async_set_config_parameter(
|
|
181
|
+
node: Node,
|
|
182
|
+
new_value: Union[int, str],
|
|
183
|
+
property_or_property_name: Union[int, str],
|
|
184
|
+
property_key: Optional[Union[int, str]] = None,
|
|
185
|
+
) -> Tuple[ConfigurationValue, CommandStatus]:
|
|
186
|
+
"""
|
|
187
|
+
Set a value for a config parameter on this node.
|
|
188
|
+
|
|
189
|
+
new_value and property_ can be provided as labels, so we need to resolve them to
|
|
190
|
+
the appropriate key
|
|
191
|
+
"""
|
|
192
|
+
config_values = node.get_configuration_values()
|
|
193
|
+
|
|
194
|
+
# If a property name is provided, we have to search for the correct value since
|
|
195
|
+
# we can't use value ID
|
|
196
|
+
if isinstance(property_or_property_name, str):
|
|
197
|
+
try:
|
|
198
|
+
zwave_value = next(
|
|
199
|
+
config_value
|
|
200
|
+
for config_value in config_values.values()
|
|
201
|
+
if config_value.property_name == property_or_property_name
|
|
202
|
+
)
|
|
203
|
+
except StopIteration:
|
|
204
|
+
raise NotFoundError(
|
|
205
|
+
"Configuration parameter with parameter name "
|
|
206
|
+
f"{property_or_property_name} could not be found"
|
|
207
|
+
) from None
|
|
208
|
+
else:
|
|
209
|
+
value_id = get_value_id(
|
|
210
|
+
node,
|
|
211
|
+
CommandClass.CONFIGURATION,
|
|
212
|
+
property_or_property_name,
|
|
213
|
+
endpoint=0,
|
|
214
|
+
property_key=property_key,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
if value_id not in config_values:
|
|
218
|
+
raise NotFoundError(
|
|
219
|
+
f"Configuration parameter with value ID {value_id} could not be "
|
|
220
|
+
"found"
|
|
221
|
+
) from None
|
|
222
|
+
zwave_value = config_values[value_id]
|
|
223
|
+
|
|
224
|
+
new_value = _validate_and_transform_new_value(zwave_value, new_value)
|
|
225
|
+
|
|
118
226
|
# Finally attempt to set the value and return the Value object if successful
|
|
119
|
-
|
|
227
|
+
success = await node.async_set_value(zwave_value, new_value)
|
|
228
|
+
if success is False:
|
|
120
229
|
raise SetValueFailed(
|
|
121
230
|
"Unable to set value, refer to "
|
|
122
231
|
"https://zwave-js.github.io/node-zwave-js/#/api/node?id=setvalue for "
|
|
123
232
|
"possible reasons"
|
|
124
233
|
)
|
|
125
234
|
|
|
126
|
-
|
|
235
|
+
status = CommandStatus.ACCEPTED if success else CommandStatus.QUEUED
|
|
236
|
+
|
|
237
|
+
return zwave_value, status
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
zwave_js_server/__init__.py,sha256=Ey3O4Tha56uU-M92oLJmQHupCJ7B9oZmxlQTo8pGUM8,45
|
|
2
|
+
zwave_js_server/__main__.py,sha256=1gWC927sa3FwcA47ndmrRWW0HlfYVdiUarjEsccRF2k,3624
|
|
3
|
+
zwave_js_server/client.py,sha256=Tz6nKa9uZFhBgh1HTXwW6jUMauUq-oSgCBPxIW7UJcQ,10788
|
|
4
|
+
zwave_js_server/const.py,sha256=5hc0tIRBwvfDaI-QyQ9FAPTA5fSX7qAC5Lw9h21EOMQ,10887
|
|
5
|
+
zwave_js_server/dump.py,sha256=inv0Q-i0DbzEcbwXeLDiu29U2I248pPMyNUTQDp5wYY,1184
|
|
6
|
+
zwave_js_server/event.py,sha256=0Aw3NzkzKMnhS7AxBh6BwAVYXRu4zDKeUDib9mHjj8w,1772
|
|
7
|
+
zwave_js_server/exceptions.py,sha256=V3FqKQdi1ggT-NnZBuJLviH99yRmPr7dg26OGnMS9Gw,2742
|
|
8
|
+
zwave_js_server/version.py,sha256=RDFP2kSU3cCVIQbgMWggdeDnvhtVsZzzZg9pOjH7CC8,364
|
|
9
|
+
zwave_js_server/model/__init__.py,sha256=XfyKH8lxZ3CB7CbRkOr5sR-eV0GrklZiBtNPmlnCJ_8,123
|
|
10
|
+
zwave_js_server/model/association.py,sha256=FsgKAha7mw6dpk7u7zdQoNEajTyiL0S5eOYcY4M2Rx4,529
|
|
11
|
+
zwave_js_server/model/command_class.py,sha256=CPKZOJNr6T3Y-ShfFB0CDZOLmITtXm5p1cOHbnRHMaI,1118
|
|
12
|
+
zwave_js_server/model/controller.py,sha256=KcjWELFj-jUdHbnV-EafHN52Q8sYxztiwOB1XkP0faY,13140
|
|
13
|
+
zwave_js_server/model/device_class.py,sha256=XxiTRVxY-Dc5cVHfJQFc2IkUHEXRiLpL5-V49PkwMxg,1708
|
|
14
|
+
zwave_js_server/model/device_config.py,sha256=JcOC-QUiBWjWd3NM11EwJoirVTU2uMsVoUxu2ExAnCs,2715
|
|
15
|
+
zwave_js_server/model/driver.py,sha256=FLuJF2x63HjSkX6iNR4GkCKHdlg5AXTfoeezC67KVNI,1802
|
|
16
|
+
zwave_js_server/model/endpoint.py,sha256=wOa9dXZBkkG8e_cqHYwaMUzuofWPgkxr8cRcW8R41EM,1315
|
|
17
|
+
zwave_js_server/model/log_config.py,sha256=21_roDDPzxKuYl1TNiIJ0vhtPI2Zx6tzzAVwql-cbLM,1571
|
|
18
|
+
zwave_js_server/model/node.py,sha256=hPBvzDlxG1ytdXE6NNqpM1_-zR5gsGPlmBQvuzqTmKc,17526
|
|
19
|
+
zwave_js_server/model/notification.py,sha256=hflkoNjr6ZrS7D1rpdTmeVfi6h9L87EqGCVupgmBAZY,3689
|
|
20
|
+
zwave_js_server/model/value.py,sha256=2rNZ7aDsC62iSzRiqdwXnhmbXRrc08P0wPLglltg5sY,8250
|
|
21
|
+
zwave_js_server/model/version.py,sha256=FTdCCyHW69NW4CXeeuNMx339SF0tV2ZipPt24eVcl2o,1000
|
|
22
|
+
zwave_js_server/util/__init__.py,sha256=ArF1K885aW0GdVd7Lo8fl8Atf70gvsxO5Ra_WoJTG28,42
|
|
23
|
+
zwave_js_server/util/helpers.py,sha256=nWTa9KIJJ4Kg9-ZDMKUpQgzdrwe911MJYdbQWE8WYN8,1303
|
|
24
|
+
zwave_js_server/util/lock.py,sha256=KG4fGOlVY8FbFn6b2hxULRGnso3ljs2X38sRksrKxdQ,3197
|
|
25
|
+
zwave_js_server/util/node.py,sha256=rMAe1O5uGHFuSadv2fkKloE11EIh9bSKfkTNWAHirVg,9161
|
|
26
|
+
zwave_js_server_python-0.23.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
27
|
+
zwave_js_server_python-0.23.0.dist-info/METADATA,sha256=aCYXs_WzJlB4QW3xzXUTy2qFWuawFphcCYU24GKnSQU,1579
|
|
28
|
+
zwave_js_server_python-0.23.0.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
|
|
29
|
+
zwave_js_server_python-0.23.0.dist-info/entry_points.txt,sha256=_8Swg1yhKiBElo6k1fxIEd6E8uPz8PDxQpwQoZ29FZE,74
|
|
30
|
+
zwave_js_server_python-0.23.0.dist-info/top_level.txt,sha256=-hwsl-i4Av5Op_yfOHC_OP56KPmzp_iVEkeohRIN5Ng,16
|
|
31
|
+
zwave_js_server_python-0.23.0.dist-info/RECORD,,
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
zwave_js_server/__init__.py,sha256=Ey3O4Tha56uU-M92oLJmQHupCJ7B9oZmxlQTo8pGUM8,45
|
|
2
|
-
zwave_js_server/__main__.py,sha256=1gWC927sa3FwcA47ndmrRWW0HlfYVdiUarjEsccRF2k,3624
|
|
3
|
-
zwave_js_server/client.py,sha256=Tz6nKa9uZFhBgh1HTXwW6jUMauUq-oSgCBPxIW7UJcQ,10788
|
|
4
|
-
zwave_js_server/const.py,sha256=l0wTowqvJfI4eXAlVvdBWrFuZbsYTH12t7jRgLwJYJs,10139
|
|
5
|
-
zwave_js_server/dump.py,sha256=inv0Q-i0DbzEcbwXeLDiu29U2I248pPMyNUTQDp5wYY,1184
|
|
6
|
-
zwave_js_server/event.py,sha256=0Aw3NzkzKMnhS7AxBh6BwAVYXRu4zDKeUDib9mHjj8w,1772
|
|
7
|
-
zwave_js_server/exceptions.py,sha256=OYKHE_1UatceS-U0cZs36uzdXhUYyAJJ6aHltPcde9E,2624
|
|
8
|
-
zwave_js_server/version.py,sha256=RDFP2kSU3cCVIQbgMWggdeDnvhtVsZzzZg9pOjH7CC8,364
|
|
9
|
-
zwave_js_server/model/__init__.py,sha256=XfyKH8lxZ3CB7CbRkOr5sR-eV0GrklZiBtNPmlnCJ_8,123
|
|
10
|
-
zwave_js_server/model/association.py,sha256=eUCb3uOow4KiMJ95YkWP2jufQNt9HBb5ahQB8pFlFhA,529
|
|
11
|
-
zwave_js_server/model/command_class.py,sha256=ASBS2Gx6z8ghKsnHKV3a7k6zSfAoTx2-xG_B-NjHeb8,1117
|
|
12
|
-
zwave_js_server/model/controller.py,sha256=pepUanQTBGBqU8I6lxTlNnhNawgXOmuGboYPMYeScxY,13150
|
|
13
|
-
zwave_js_server/model/device_class.py,sha256=XxiTRVxY-Dc5cVHfJQFc2IkUHEXRiLpL5-V49PkwMxg,1708
|
|
14
|
-
zwave_js_server/model/device_config.py,sha256=JcOC-QUiBWjWd3NM11EwJoirVTU2uMsVoUxu2ExAnCs,2715
|
|
15
|
-
zwave_js_server/model/driver.py,sha256=D4pqsOHgWjjBAKTIiWpqZuSyBMwtTAaxCvx5UUGRvR0,1801
|
|
16
|
-
zwave_js_server/model/endpoint.py,sha256=un0SSPaKpa-n2cslj8rfwavI5PzvXX4J0X-uMc3et3Y,1056
|
|
17
|
-
zwave_js_server/model/log_config.py,sha256=LyjCBYJ8q2STQFlycfCLpIqfeMT5Up0DwhsY8xBZznk,1506
|
|
18
|
-
zwave_js_server/model/node.py,sha256=3VpdCylyysjTxL8WWgAr3-OTbhuWrya687TT6Eg6RsU,16721
|
|
19
|
-
zwave_js_server/model/notification.py,sha256=9nuQS6lpAr7zqk8odZQbgmUTW3xsoC2P6TfyydcN1iw,1189
|
|
20
|
-
zwave_js_server/model/value.py,sha256=zX3KbpPv-5rqU2jIuezf5PQVhnaOJSvLEGspXnhg5Ao,8122
|
|
21
|
-
zwave_js_server/model/version.py,sha256=FTdCCyHW69NW4CXeeuNMx339SF0tV2ZipPt24eVcl2o,1000
|
|
22
|
-
zwave_js_server/util/__init__.py,sha256=ArF1K885aW0GdVd7Lo8fl8Atf70gvsxO5Ra_WoJTG28,42
|
|
23
|
-
zwave_js_server/util/helpers.py,sha256=WMXhcODwE1UU6E9LZca_tdKQxifZVTH4IO3UcszdgbA,996
|
|
24
|
-
zwave_js_server/util/lock.py,sha256=jdEU0eyS_9TnZYz-BMU4amUsNFplSsoRpSBFHUWlHKc,3197
|
|
25
|
-
zwave_js_server/util/node.py,sha256=N5JCXxhQe1sjbOK9K9S7gD6mk8kx8bv6uMeKRpnBHjY,4566
|
|
26
|
-
zwave_js_server_python-0.22.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
27
|
-
zwave_js_server_python-0.22.0.dist-info/METADATA,sha256=rUqNTy1yXTTAAzB-h8WuGIPq-qw-vicMIqJ6Zj3ApfE,1579
|
|
28
|
-
zwave_js_server_python-0.22.0.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
|
|
29
|
-
zwave_js_server_python-0.22.0.dist-info/entry_points.txt,sha256=_8Swg1yhKiBElo6k1fxIEd6E8uPz8PDxQpwQoZ29FZE,74
|
|
30
|
-
zwave_js_server_python-0.22.0.dist-info/top_level.txt,sha256=-hwsl-i4Av5Op_yfOHC_OP56KPmzp_iVEkeohRIN5Ng,16
|
|
31
|
-
zwave_js_server_python-0.22.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{zwave_js_server_python-0.22.0.dist-info → zwave_js_server_python-0.23.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{zwave_js_server_python-0.22.0.dist-info → zwave_js_server_python-0.23.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|