zwave-js-server-python 0.56.0__py3-none-any.whl → 0.58.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.
@@ -8,12 +8,12 @@ import logging
8
8
  from typing import TypedDict
9
9
 
10
10
  PACKAGE_NAME = "zwave-js-server-python"
11
- __version__ = "0.56.0"
11
+ __version__ = "0.58.0"
12
12
 
13
13
  # minimal server schema version we can handle
14
- MIN_SERVER_SCHEMA_VERSION = 35
14
+ MIN_SERVER_SCHEMA_VERSION = 37
15
15
  # max server schema version we can handle (and our code is compatible with)
16
- MAX_SERVER_SCHEMA_VERSION = 35
16
+ MAX_SERVER_SCHEMA_VERSION = 37
17
17
 
18
18
  VALUE_UNKNOWN = "unknown"
19
19
 
@@ -505,3 +505,16 @@ class SupervisionStatus(IntEnum):
505
505
  WORKING = 1
506
506
  FAIL = 2
507
507
  SUCCESS = 255
508
+
509
+
510
+ class AssociationCheckResult(IntEnum):
511
+ """Enum for all known association check results."""
512
+
513
+ # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/lib/_Types.ts#L47
514
+ OK = 1
515
+ FORBIDDEN_DESTINATION_IS_LONG_RANGE = 2
516
+ FORBIDDEN_SOURCE_IS_LONG_RANGE = 3
517
+ FORBIDDEN_SELF_ASSOCIATION = 4
518
+ FORBIDDEN_SECURITY_CLASS_MISMATCH = 5
519
+ FORBIDDEN_DESTINATION_SECURITY_CLASS_NOT_GRANTED = 6
520
+ FORBIDDEN_NO_SUPPORTED_CCS = 7
@@ -186,6 +186,7 @@ class DoorLockCCConfigurationSetOptions:
186
186
  ),
187
187
  )
188
188
  for prop_name, val in (
189
+ (TARGET_LOCK_TIMEOUT_PROPERTY, self.lock_timeout_configuration),
189
190
  (TARGET_AUTO_RELOCK_TIME_PROPERTY, self.auto_relock_time),
190
191
  (TARGET_HOLD_AND_RELEASE_TIME_PROPERTY, self.hold_and_release_time),
191
192
  (TARGET_TWIST_ASSIST_PROPERTY, self.twist_assist),
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  from enum import IntEnum
6
6
 
7
7
  VALUE_PROPERTY = "value"
8
+ RESET_PROPERTY = "reset"
8
9
 
9
10
  CC_SPECIFIC_SCALE = "scale"
10
11
  CC_SPECIFIC_METER_TYPE = "meterType"
@@ -13,9 +14,11 @@ CC_SPECIFIC_RATE_TYPE = "rateType"
13
14
  RESET_METER_CC_API = "reset"
14
15
 
15
16
  # optional attributes when calling the Meter CC reset API.
16
- # https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/MeterCC.ts#L873-L881
17
+ # https://github.com/zwave-js/node-zwave-js/blob/master/packages/cc/src/cc/MeterCC.ts
17
18
  RESET_METER_OPTION_TARGET_VALUE = "targetValue"
18
19
  RESET_METER_OPTION_TYPE = "type"
20
+ RESET_METER_OPTION_SCALE = "scale"
21
+ RESET_METER_OPTION_RATE_TYPE = "rateType"
19
22
 
20
23
 
21
24
  # https://github.com/zwave-js/node-zwave-js/blob/master/packages/config/config/meters.json
zwave_js_server/event.py CHANGED
@@ -21,6 +21,14 @@ class BaseEventModel(BaseModel):
21
21
  source: Literal["controller", "driver", "node"]
22
22
  event: str
23
23
 
24
+ @classmethod
25
+ def from_dict(cls, data: dict) -> BaseEventModel:
26
+ """Initialize from dict."""
27
+ return cls(
28
+ source=data["source"],
29
+ event=data["event"],
30
+ )
31
+
24
32
 
25
33
  @dataclass
26
34
  class Event:
@@ -3,6 +3,11 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from dataclasses import dataclass, field
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from .controller import Controller
10
+ from .node import Node
6
11
 
7
12
 
8
13
  @dataclass
@@ -21,5 +26,13 @@ class AssociationGroup:
21
26
  class AssociationAddress:
22
27
  """Represent a association dict type."""
23
28
 
29
+ controller: Controller
24
30
  node_id: int
25
31
  endpoint: int | None = None
32
+
33
+ @property
34
+ def node(self) -> Node | None:
35
+ """Return the node."""
36
+ if self.node_id in self.controller.nodes:
37
+ return self.controller.nodes[self.node_id]
38
+ return None
@@ -51,3 +51,7 @@ class CommandClassInfo:
51
51
  def is_secure(self) -> bool:
52
52
  """Return if the CommandClass is used securely on this node/endpoint."""
53
53
  return self.data["isSecure"]
54
+
55
+ def to_dict(self) -> CommandClassInfoDataType:
56
+ """Create a dictionary from itself."""
57
+ return self.data.copy()
@@ -9,6 +9,7 @@ from zwave_js_server.model.node.firmware import NodeFirmwareUpdateInfo
9
9
 
10
10
  from ...const import (
11
11
  MINIMUM_QR_STRING_LENGTH,
12
+ AssociationCheckResult,
12
13
  ControllerStatus,
13
14
  ExclusionStrategy,
14
15
  InclusionState,
@@ -574,6 +575,7 @@ class Controller(EventBase):
574
575
  for key, association_addresses in data["associations"].items():
575
576
  associations[int(key)] = [
576
577
  AssociationAddress(
578
+ self,
577
579
  node_id=association_address["nodeId"],
578
580
  endpoint=association_address.get("endpoint"),
579
581
  )
@@ -581,10 +583,10 @@ class Controller(EventBase):
581
583
  ]
582
584
  return associations
583
585
 
584
- async def async_is_association_allowed(
586
+ async def async_check_association(
585
587
  self, source: AssociationAddress, group: int, association: AssociationAddress
586
- ) -> bool:
587
- """Send isAssociationAllowed command to Controller."""
588
+ ) -> AssociationCheckResult:
589
+ """Send checkAssociation command to Controller."""
588
590
  source_data = {"nodeId": source.node_id}
589
591
  if source.endpoint is not None:
590
592
  source_data["endpoint"] = source.endpoint
@@ -594,13 +596,14 @@ class Controller(EventBase):
594
596
  association_data["endpoint"] = association.endpoint
595
597
  data = await self.client.async_send_command(
596
598
  {
597
- "command": "controller.is_association_allowed",
599
+ "command": "controller.check_association",
598
600
  **source_data,
599
601
  "group": group,
600
602
  "association": association_data,
601
- }
603
+ },
604
+ require_schema=37,
602
605
  )
603
- return cast(bool, data["allowed"])
606
+ return AssociationCheckResult(data["result"])
604
607
 
605
608
  async def async_add_associations(
606
609
  self,
@@ -869,7 +872,7 @@ class Controller(EventBase):
869
872
  f"{event.data}"
870
873
  )
871
874
 
872
- CONTROLLER_EVENT_MODEL_MAP[event.type](**event.data)
875
+ CONTROLLER_EVENT_MODEL_MAP[event.type].from_dict(event.data)
873
876
 
874
877
  self._handle_event_protocol(event)
875
878
 
@@ -52,6 +52,15 @@ class FirmwareUpdateFinishedEventModel(BaseControllerEventModel):
52
52
  event: Literal["firmware update finished"]
53
53
  result: ControllerFirmwareUpdateResultDataType
54
54
 
55
+ @classmethod
56
+ def from_dict(cls, data: dict) -> FirmwareUpdateFinishedEventModel:
57
+ """Initialize from dict."""
58
+ return cls(
59
+ source=data["source"],
60
+ event=data["event"],
61
+ result=data["result"],
62
+ )
63
+
55
64
 
56
65
  class FirmwareUpdateProgressEventModel(BaseControllerEventModel):
57
66
  """Model for `firmware update progress` event data."""
@@ -59,6 +68,15 @@ class FirmwareUpdateProgressEventModel(BaseControllerEventModel):
59
68
  event: Literal["firmware update progress"]
60
69
  progress: ControllerFirmwareUpdateProgressDataType
61
70
 
71
+ @classmethod
72
+ def from_dict(cls, data: dict) -> FirmwareUpdateProgressEventModel:
73
+ """Initialize from dict."""
74
+ return cls(
75
+ source=data["source"],
76
+ event=data["event"],
77
+ progress=data["progress"],
78
+ )
79
+
62
80
 
63
81
  class GrantSecurityClassesEventModel(BaseControllerEventModel):
64
82
  """Model for `grant security classes` event data."""
@@ -66,6 +84,15 @@ class GrantSecurityClassesEventModel(BaseControllerEventModel):
66
84
  event: Literal["grant security classes"]
67
85
  requested: InclusionGrantDataType
68
86
 
87
+ @classmethod
88
+ def from_dict(cls, data: dict) -> GrantSecurityClassesEventModel:
89
+ """Initialize from dict."""
90
+ return cls(
91
+ source=data["source"],
92
+ event=data["event"],
93
+ requested=data["requested"],
94
+ )
95
+
69
96
 
70
97
  class RebuildRoutesDoneEventModel(BaseControllerEventModel):
71
98
  """Model for `rebuild routes done` event data."""
@@ -73,6 +100,15 @@ class RebuildRoutesDoneEventModel(BaseControllerEventModel):
73
100
  event: Literal["rebuild routes done"]
74
101
  result: dict[str, str]
75
102
 
103
+ @classmethod
104
+ def from_dict(cls, data: dict) -> RebuildRoutesDoneEventModel:
105
+ """Initialize from dict."""
106
+ return cls(
107
+ source=data["source"],
108
+ event=data["event"],
109
+ result=data["result"],
110
+ )
111
+
76
112
 
77
113
  class RebuildRoutesProgressEventModel(BaseControllerEventModel):
78
114
  """Model for `rebuild routes progress` event data."""
@@ -80,6 +116,15 @@ class RebuildRoutesProgressEventModel(BaseControllerEventModel):
80
116
  event: Literal["rebuild routes progress"]
81
117
  progress: dict[str, str]
82
118
 
119
+ @classmethod
120
+ def from_dict(cls, data: dict) -> RebuildRoutesProgressEventModel:
121
+ """Initialize from dict."""
122
+ return cls(
123
+ source=data["source"],
124
+ event=data["event"],
125
+ progress=data["progress"],
126
+ )
127
+
83
128
 
84
129
  class InclusionAbortedEventModel(BaseControllerEventModel):
85
130
  """Model for `inclusion aborted` event data."""
@@ -99,6 +144,15 @@ class InclusionStartedEventModel(BaseControllerEventModel):
99
144
  event: Literal["inclusion started"]
100
145
  secure: bool
101
146
 
147
+ @classmethod
148
+ def from_dict(cls, data: dict) -> InclusionStartedEventModel:
149
+ """Initialize from dict."""
150
+ return cls(
151
+ source=data["source"],
152
+ event=data["event"],
153
+ secure=data["secure"],
154
+ )
155
+
102
156
 
103
157
  class InclusionStoppedEventModel(BaseControllerEventModel):
104
158
  """Model for `inclusion stopped` event data."""
@@ -113,6 +167,16 @@ class NodeAddedEventModel(BaseControllerEventModel):
113
167
  node: NodeDataType
114
168
  result: InclusionResultDataType
115
169
 
170
+ @classmethod
171
+ def from_dict(cls, data: dict) -> NodeAddedEventModel:
172
+ """Initialize from dict."""
173
+ return cls(
174
+ source=data["source"],
175
+ event=data["event"],
176
+ node=data["node"],
177
+ result=data["result"],
178
+ )
179
+
116
180
 
117
181
  class NodeFoundEventModel(BaseControllerEventModel):
118
182
  """Model for `node found` event data."""
@@ -120,6 +184,15 @@ class NodeFoundEventModel(BaseControllerEventModel):
120
184
  event: Literal["node found"]
121
185
  node: FoundNodeDataType
122
186
 
187
+ @classmethod
188
+ def from_dict(cls, data: dict) -> NodeFoundEventModel:
189
+ """Initialize from dict."""
190
+ return cls(
191
+ source=data["source"],
192
+ event=data["event"],
193
+ node=data["node"],
194
+ )
195
+
123
196
 
124
197
  class NodeRemovedEventModel(BaseControllerEventModel):
125
198
  """Model for `node removed` event data."""
@@ -128,6 +201,16 @@ class NodeRemovedEventModel(BaseControllerEventModel):
128
201
  node: NodeDataType
129
202
  reason: RemoveNodeReason
130
203
 
204
+ @classmethod
205
+ def from_dict(cls, data: dict) -> NodeRemovedEventModel:
206
+ """Initialize from dict."""
207
+ return cls(
208
+ source=data["source"],
209
+ event=data["event"],
210
+ node=data["node"],
211
+ reason=data["reason"],
212
+ )
213
+
131
214
 
132
215
  class NVMBackupAndConvertProgressEventModel(BaseControllerEventModel):
133
216
  """Base model for `nvm backup progress` and `nvm convert progress` event data."""
@@ -135,6 +218,16 @@ class NVMBackupAndConvertProgressEventModel(BaseControllerEventModel):
135
218
  bytesRead: int
136
219
  total: int
137
220
 
221
+ @classmethod
222
+ def from_dict(cls, data: dict) -> NVMBackupAndConvertProgressEventModel:
223
+ """Initialize from dict."""
224
+ return cls(
225
+ source=data["source"],
226
+ event=data["event"],
227
+ bytesRead=data["bytesRead"],
228
+ total=data["total"],
229
+ )
230
+
138
231
 
139
232
  class NVMBackupProgressEventModel(NVMBackupAndConvertProgressEventModel):
140
233
  """Model for `nvm backup progress` event data."""
@@ -155,6 +248,16 @@ class NVMRestoreProgressEventModel(BaseControllerEventModel):
155
248
  bytesWritten: int
156
249
  total: int
157
250
 
251
+ @classmethod
252
+ def from_dict(cls, data: dict) -> NVMRestoreProgressEventModel:
253
+ """Initialize from dict."""
254
+ return cls(
255
+ source=data["source"],
256
+ event=data["event"],
257
+ bytesWritten=data["bytesWritten"],
258
+ total=data["total"],
259
+ )
260
+
158
261
 
159
262
  class StatisticsUpdatedEventModel(BaseControllerEventModel):
160
263
  """Model for `statistics updated` event data."""
@@ -162,6 +265,15 @@ class StatisticsUpdatedEventModel(BaseControllerEventModel):
162
265
  event: Literal["statistics updated"]
163
266
  statistics: ControllerStatisticsDataType
164
267
 
268
+ @classmethod
269
+ def from_dict(cls, data: dict) -> StatisticsUpdatedEventModel:
270
+ """Initialize from dict."""
271
+ return cls(
272
+ source=data["source"],
273
+ event=data["event"],
274
+ statistics=data["statistics"],
275
+ )
276
+
165
277
 
166
278
  class ValidateDSKAndEnterPINEventModel(BaseControllerEventModel):
167
279
  """Model for `validate dsk and enter pin` event data."""
@@ -169,6 +281,15 @@ class ValidateDSKAndEnterPINEventModel(BaseControllerEventModel):
169
281
  event: Literal["validate dsk and enter pin"]
170
282
  dsk: str
171
283
 
284
+ @classmethod
285
+ def from_dict(cls, data: dict) -> ValidateDSKAndEnterPINEventModel:
286
+ """Initialize from dict."""
287
+ return cls(
288
+ source=data["source"],
289
+ event=data["event"],
290
+ dsk=data["dsk"],
291
+ )
292
+
172
293
 
173
294
  class IdentifyEventModel(BaseControllerEventModel):
174
295
  """Model for `identify` event data."""
@@ -176,6 +297,15 @@ class IdentifyEventModel(BaseControllerEventModel):
176
297
  event: Literal["identify"]
177
298
  nodeId: int
178
299
 
300
+ @classmethod
301
+ def from_dict(cls, data: dict) -> IdentifyEventModel:
302
+ """Initialize from dict."""
303
+ return cls(
304
+ source=data["source"],
305
+ event=data["event"],
306
+ nodeId=data["nodeId"],
307
+ )
308
+
179
309
 
180
310
  class StatusChangedEventModel(BaseControllerEventModel):
181
311
  """Model for `status changed` event data."""
@@ -183,6 +313,15 @@ class StatusChangedEventModel(BaseControllerEventModel):
183
313
  event: Literal["status changed"]
184
314
  status: int
185
315
 
316
+ @classmethod
317
+ def from_dict(cls, data: dict) -> StatusChangedEventModel:
318
+ """Initialize from dict."""
319
+ return cls(
320
+ source=data["source"],
321
+ event=data["event"],
322
+ status=data["status"],
323
+ )
324
+
186
325
 
187
326
  CONTROLLER_EVENT_MODEL_MAP: dict[str, type[BaseControllerEventModel]] = {
188
327
  "exclusion failed": ExclusionFailedEventModel,
@@ -76,13 +76,13 @@ class ProvisioningEntry:
76
76
  security_classes=[
77
77
  SecurityClass(sec_cls) for sec_cls in data["securityClasses"]
78
78
  ],
79
- additional_properties={
80
- k: v
81
- for k, v in data.items()
82
- if k
83
- not in {"dsk", "securityClasses", "requestedSecurityClasses", "status"}
84
- },
85
79
  )
80
+ if additional_properties := {
81
+ k: v
82
+ for k, v in data.items()
83
+ if k not in ("dsk", "securityClasses", "requestedSecurityClasses", "status")
84
+ }:
85
+ cls_instance.additional_properties = additional_properties
86
86
  if "requestedSecurityClasses" in data:
87
87
  cls_instance.requested_security_classes = [
88
88
  SecurityClass(sec_cls) for sec_cls in data["requestedSecurityClasses"]
@@ -148,6 +148,12 @@ class QRProvisioningInformation(ProvisioningEntry, QRProvisioningInformationMixi
148
148
  @classmethod
149
149
  def from_dict(cls, data: dict[str, Any]) -> QRProvisioningInformation:
150
150
  """Return QRProvisioningInformation from data dict."""
151
+ supported_protocols: list[Protocols] | None = None
152
+ if "supportedProtocols" in data:
153
+ supported_protocols = [
154
+ Protocols(supported_protocol)
155
+ for supported_protocol in data["supportedProtocols"]
156
+ ]
151
157
  cls_instance = cls(
152
158
  version=QRCodeVersion(data["version"]),
153
159
  security_classes=[
@@ -163,33 +169,31 @@ class QRProvisioningInformation(ProvisioningEntry, QRProvisioningInformationMixi
163
169
  application_version=data["applicationVersion"],
164
170
  max_inclusion_request_interval=data.get("maxInclusionRequestInterval"),
165
171
  uuid=data.get("uuid"),
166
- supported_protocols=[
167
- Protocols(supported_protocol)
168
- for supported_protocol in data.get("supportedProtocols", [])
169
- ],
170
- additional_properties={
171
- k: v
172
- for k, v in data.items()
173
- if k
174
- not in {
175
- "version",
176
- "securityClasses",
177
- "requestedSecurityClasses",
178
- "dsk",
179
- "genericDeviceClass",
180
- "specificDeviceClass",
181
- "installerIconType",
182
- "manufacturerId",
183
- "productType",
184
- "productId",
185
- "applicationVersion",
186
- "maxInclusionRequestInterval",
187
- "uuid",
188
- "supportedProtocols",
189
- "status",
190
- }
191
- },
172
+ supported_protocols=supported_protocols,
192
173
  )
174
+ if additional_properties := {
175
+ k: v
176
+ for k, v in data.items()
177
+ if k
178
+ not in (
179
+ "version",
180
+ "securityClasses",
181
+ "requestedSecurityClasses",
182
+ "dsk",
183
+ "genericDeviceClass",
184
+ "specificDeviceClass",
185
+ "installerIconType",
186
+ "manufacturerId",
187
+ "productType",
188
+ "productId",
189
+ "applicationVersion",
190
+ "maxInclusionRequestInterval",
191
+ "uuid",
192
+ "supportedProtocols",
193
+ "status",
194
+ )
195
+ }:
196
+ cls_instance.additional_properties = additional_properties
193
197
  if "requestedSecurityClasses" in data:
194
198
  cls_instance.requested_security_classes = [
195
199
  SecurityClass(sec_cls) for sec_cls in data["requestedSecurityClasses"]
@@ -23,8 +23,6 @@ class DeviceClassDataType(TypedDict):
23
23
  basic: DeviceClassItemDataType
24
24
  generic: DeviceClassItemDataType
25
25
  specific: DeviceClassItemDataType
26
- mandatorySupportedCCs: list[int]
27
- mandatoryControlledCCs: list[int]
28
26
 
29
27
 
30
28
  @dataclass
@@ -40,11 +38,18 @@ class DeviceClass:
40
38
 
41
39
  def __init__(self, data: DeviceClassDataType) -> None:
42
40
  """Initialize."""
43
- self._basic = DeviceClassItem(**data["basic"])
44
- self._generic = DeviceClassItem(**data["generic"])
45
- self._specific = DeviceClassItem(**data["specific"])
46
- self._mandatory_supported_ccs: list[int] = data["mandatorySupportedCCs"]
47
- self._mandatory_controlled_ccs: list[int] = data["mandatoryControlledCCs"]
41
+ self._basic = DeviceClassItem(
42
+ key=data["basic"]["key"],
43
+ label=data["basic"]["label"],
44
+ )
45
+ self._generic = DeviceClassItem(
46
+ key=data["generic"]["key"],
47
+ label=data["generic"]["label"],
48
+ )
49
+ self._specific = DeviceClassItem(
50
+ key=data["specific"]["key"],
51
+ label=data["specific"]["label"],
52
+ )
48
53
 
49
54
  @property
50
55
  def basic(self) -> DeviceClassItem:
@@ -60,13 +65,3 @@ class DeviceClass:
60
65
  def specific(self) -> DeviceClassItem:
61
66
  """Return specific DeviceClass."""
62
67
  return self._specific
63
-
64
- @property
65
- def mandatory_supported_ccs(self) -> list[int]:
66
- """Return list of mandatory Supported CC id's."""
67
- return self._mandatory_supported_ccs
68
-
69
- @property
70
- def mandatory_controlled_ccs(self) -> list[int]:
71
- """Return list of mandatory Controlled CC id's."""
72
- return self._mandatory_controlled_ccs
@@ -30,6 +30,15 @@ class LogConfigUpdatedEventModel(BaseDriverEventModel):
30
30
  event: Literal["log config updated"]
31
31
  config: LogConfigDataType
32
32
 
33
+ @classmethod
34
+ def from_dict(cls, data: dict) -> LogConfigUpdatedEventModel:
35
+ """Initialize from dict."""
36
+ return cls(
37
+ source=data["source"],
38
+ event=data["event"],
39
+ config=data["config"],
40
+ )
41
+
33
42
 
34
43
  class AllNodesReadyEventModel(BaseDriverEventModel):
35
44
  """Model for `all nodes ready` event data."""
@@ -87,7 +96,7 @@ class Driver(EventBase):
87
96
  self.controller.receive_event(event)
88
97
  return
89
98
 
90
- DRIVER_EVENT_MODEL_MAP[event.type](**event.data)
99
+ DRIVER_EVENT_MODEL_MAP[event.type].from_dict(event.data)
91
100
 
92
101
  self._handle_event_protocol(event)
93
102
 
@@ -19,12 +19,7 @@ from ...const import (
19
19
  SecurityClass,
20
20
  )
21
21
  from ...event import Event, EventBase
22
- from ...exceptions import (
23
- FailedCommand,
24
- NotFoundError,
25
- UnparseableValue,
26
- UnwriteableValue,
27
- )
22
+ from ...exceptions import NotFoundError, UnparseableValue, UnwriteableValue
28
23
  from ..command_class import CommandClassInfo
29
24
  from ..device_class import DeviceClass
30
25
  from ..device_config import DeviceConfig
@@ -50,7 +45,6 @@ from ..value import (
50
45
  ValueMetadata,
51
46
  ValueNotification,
52
47
  _get_value_id_str_from_dict,
53
- _init_value,
54
48
  )
55
49
  from .data_model import NodeDataType
56
50
  from .event_model import NODE_EVENT_MODEL_MAP
@@ -139,6 +133,12 @@ class Node(EventBase):
139
133
  self.client.driver == other.client.driver and self.node_id == other.node_id
140
134
  )
141
135
 
136
+ def _init_value(self, val: ValueDataType) -> Value | ConfigurationValue:
137
+ """Initialize a Value object from ValueDataType."""
138
+ if val["commandClass"] == CommandClass.CONFIGURATION:
139
+ return ConfigurationValue(self, val)
140
+ return Value(self, val)
141
+
142
142
  @property
143
143
  def node_id(self) -> int:
144
144
  """Return node ID property."""
@@ -429,7 +429,7 @@ class Node(EventBase):
429
429
  if value_id in self.values:
430
430
  self.values[value_id].update(val)
431
431
  else:
432
- self.values[value_id] = _init_value(self, val)
432
+ self.values[value_id] = self._init_value(val)
433
433
  except UnparseableValue:
434
434
  # If we can't parse the value, don't store it
435
435
  pass
@@ -448,8 +448,9 @@ class Node(EventBase):
448
448
  )
449
449
  if last_seen := data.get("lastSeen"):
450
450
  self._last_seen = datetime.fromisoformat(last_seen)
451
- if not self._statistics.last_seen:
451
+ if not self._statistics.last_seen and self.last_seen:
452
452
  self._statistics.last_seen = self.last_seen
453
+ self._statistics.data["lastSeen"] = self.last_seen.isoformat()
453
454
 
454
455
  self._update_values(self.data.pop("values"))
455
456
  self._update_endpoints(self.data.pop("endpoints"))
@@ -474,7 +475,7 @@ class Node(EventBase):
474
475
 
475
476
  def receive_event(self, event: Event) -> None:
476
477
  """Receive an event."""
477
- NODE_EVENT_MODEL_MAP[event.type](**event.data)
478
+ NODE_EVENT_MODEL_MAP[event.type].from_dict(event.data)
478
479
 
479
480
  self._handle_event_protocol(event)
480
481
  event.data["node"] = self
@@ -593,12 +594,9 @@ class Node(EventBase):
593
594
  data = await self.async_send_command(
594
595
  "get_defined_value_ids", wait_for_result=True
595
596
  )
596
-
597
- if data is None:
598
- # We should never reach this code
599
- raise FailedCommand("Command failed", "failed_command")
597
+ assert data
600
598
  return [
601
- _init_value(self, cast(ValueDataType, value_id))
599
+ self._init_value(cast(ValueDataType, value_id))
602
600
  for value_id in data["valueIds"]
603
601
  ]
604
602
 
@@ -1061,7 +1059,7 @@ class Node(EventBase):
1061
1059
  value_id = _get_value_id_str_from_dict(self, evt_val_data)
1062
1060
  value = self.values.get(value_id)
1063
1061
  if value is None:
1064
- value = _init_value(self, evt_val_data)
1062
+ value = self._init_value(evt_val_data)
1065
1063
  self.values[value.value_id] = event.data["value"] = value
1066
1064
  else:
1067
1065
  value.receive_event(event)
@@ -32,6 +32,15 @@ class BaseNodeEventModel(BaseEventModel):
32
32
  source: Literal["node"]
33
33
  nodeId: int
34
34
 
35
+ @classmethod
36
+ def from_dict(cls, data: dict) -> BaseNodeEventModel:
37
+ """Initialize from dict."""
38
+ return cls(
39
+ source=data["source"],
40
+ event=data["event"],
41
+ nodeId=data["nodeId"],
42
+ )
43
+
35
44
 
36
45
  class AliveEventModel(BaseNodeEventModel):
37
46
  """Model for `alive` event data."""
@@ -50,6 +59,18 @@ class CheckHealthProgressEventModel(BaseNodeEventModel):
50
59
  totalRounds: int
51
60
  lastRating: int
52
61
 
62
+ @classmethod
63
+ def from_dict(cls, data: dict) -> CheckHealthProgressEventModel:
64
+ """Initialize from dict."""
65
+ return cls(
66
+ source=data["source"],
67
+ event=data["event"],
68
+ nodeId=data["nodeId"],
69
+ rounds=data["rounds"],
70
+ totalRounds=data["totalRounds"],
71
+ lastRating=data["lastRating"],
72
+ )
73
+
53
74
 
54
75
  class CheckLifelineHealthProgressEventModel(CheckHealthProgressEventModel):
55
76
  """Model for `check lifeline health progress` event data."""
@@ -83,6 +104,19 @@ class InterviewFailedEventArgsModel(BaseModel):
83
104
  attempt: int | None
84
105
  maxAttempts: int | None
85
106
 
107
+ @classmethod
108
+ def from_dict(cls, data: dict) -> InterviewFailedEventArgsModel:
109
+ """Initialize from dict."""
110
+ return cls(
111
+ source=data["source"],
112
+ event=data["event"],
113
+ nodeId=data["nodeId"],
114
+ errorMessage=data["errorMessage"],
115
+ isFinal=data["isFinal"],
116
+ attempt=data["attempt"],
117
+ maxAttempts=data["maxAttempts"],
118
+ )
119
+
86
120
 
87
121
  class InterviewFailedEventModel(BaseNodeEventModel):
88
122
  """Model for `interview failed` event data."""
@@ -90,6 +124,16 @@ class InterviewFailedEventModel(BaseNodeEventModel):
90
124
  event: Literal["interview failed"]
91
125
  args: InterviewFailedEventArgsModel
92
126
 
127
+ @classmethod
128
+ def from_dict(cls, data: dict) -> InterviewFailedEventModel:
129
+ """Initialize from dict."""
130
+ return cls(
131
+ source=data["source"],
132
+ event=data["event"],
133
+ nodeId=data["nodeId"],
134
+ args=data["args"],
135
+ )
136
+
93
137
 
94
138
  class InterviewStageCompletedEventModel(BaseNodeEventModel):
95
139
  """Model for `interview stage completed` event data."""
@@ -97,6 +141,16 @@ class InterviewStageCompletedEventModel(BaseNodeEventModel):
97
141
  event: Literal["interview stage completed"]
98
142
  stageName: str
99
143
 
144
+ @classmethod
145
+ def from_dict(cls, data: dict) -> InterviewStageCompletedEventModel:
146
+ """Initialize from dict."""
147
+ return cls(
148
+ source=data["source"],
149
+ event=data["event"],
150
+ nodeId=data["nodeId"],
151
+ stageName=data["stageName"],
152
+ )
153
+
100
154
 
101
155
  class InterviewStartedEventModel(BaseNodeEventModel):
102
156
  """Model for `interview started` event data."""
@@ -118,6 +172,18 @@ class NotificationEventModel(BaseNodeEventModel):
118
172
  | MultilevelSwitchNotificationArgsDataType
119
173
  )
120
174
 
175
+ @classmethod
176
+ def from_dict(cls, data: dict) -> NotificationEventModel:
177
+ """Initialize from dict."""
178
+ return cls(
179
+ source=data["source"],
180
+ event=data["event"],
181
+ nodeId=data["nodeId"],
182
+ endpointIndex=data["endpointIndex"],
183
+ ccId=data["ccId"],
184
+ args=data["args"],
185
+ )
186
+
121
187
 
122
188
  class ReadyEventModel(BaseNodeEventModel):
123
189
  """Model for `ready` event data."""
@@ -125,6 +191,16 @@ class ReadyEventModel(BaseNodeEventModel):
125
191
  event: Literal["ready"]
126
192
  nodeState: NodeDataType
127
193
 
194
+ @classmethod
195
+ def from_dict(cls, data: dict) -> ReadyEventModel:
196
+ """Initialize from dict."""
197
+ return cls(
198
+ source=data["source"],
199
+ event=data["event"],
200
+ nodeId=data["nodeId"],
201
+ nodeState=data["nodeState"],
202
+ )
203
+
128
204
 
129
205
  class SleepEventModel(BaseNodeEventModel):
130
206
  """Model for `sleep` event data."""
@@ -138,6 +214,16 @@ class StatisticsUpdatedEventModel(BaseNodeEventModel):
138
214
  event: Literal["statistics updated"]
139
215
  statistics: NodeStatisticsDataType
140
216
 
217
+ @classmethod
218
+ def from_dict(cls, data: dict) -> StatisticsUpdatedEventModel:
219
+ """Initialize from dict."""
220
+ return cls(
221
+ source=data["source"],
222
+ event=data["event"],
223
+ nodeId=data["nodeId"],
224
+ statistics=data["statistics"],
225
+ )
226
+
141
227
 
142
228
  class TestPowerLevelProgressEventModel(BaseNodeEventModel):
143
229
  """Model for `test powerlevel progress` event data."""
@@ -146,6 +232,17 @@ class TestPowerLevelProgressEventModel(BaseNodeEventModel):
146
232
  acknowledged: int
147
233
  total: int
148
234
 
235
+ @classmethod
236
+ def from_dict(cls, data: dict) -> TestPowerLevelProgressEventModel:
237
+ """Initialize from dict."""
238
+ return cls(
239
+ source=data["source"],
240
+ event=data["event"],
241
+ nodeId=data["nodeId"],
242
+ acknowledged=data["acknowledged"],
243
+ total=data["total"],
244
+ )
245
+
149
246
 
150
247
  class ValueEventModel(BaseNodeEventModel):
151
248
  """
@@ -157,6 +254,16 @@ class ValueEventModel(BaseNodeEventModel):
157
254
 
158
255
  args: ValueDataType
159
256
 
257
+ @classmethod
258
+ def from_dict(cls, data: dict) -> ValueEventModel:
259
+ """Initialize from dict."""
260
+ return cls(
261
+ source=data["source"],
262
+ event=data["event"],
263
+ nodeId=data["nodeId"],
264
+ args=data["args"],
265
+ )
266
+
160
267
 
161
268
  class MetadataUpdatedEventModel(ValueEventModel):
162
269
  """Model for `metadata updated` event data."""
@@ -200,6 +307,16 @@ class FirmwareUpdateFinishedEventModel(BaseNodeEventModel):
200
307
  event: Literal["firmware update finished"]
201
308
  result: NodeFirmwareUpdateResultDataType
202
309
 
310
+ @classmethod
311
+ def from_dict(cls, data: dict) -> FirmwareUpdateFinishedEventModel:
312
+ """Initialize from dict."""
313
+ return cls(
314
+ source=data["source"],
315
+ event=data["event"],
316
+ nodeId=data["nodeId"],
317
+ result=data["result"],
318
+ )
319
+
203
320
 
204
321
  class FirmwareUpdateProgressEventModel(BaseNodeEventModel):
205
322
  """Model for `firmware update progress` event data."""
@@ -207,6 +324,16 @@ class FirmwareUpdateProgressEventModel(BaseNodeEventModel):
207
324
  event: Literal["firmware update progress"]
208
325
  progress: NodeFirmwareUpdateProgressDataType
209
326
 
327
+ @classmethod
328
+ def from_dict(cls, data: dict) -> FirmwareUpdateProgressEventModel:
329
+ """Initialize from dict."""
330
+ return cls(
331
+ source=data["source"],
332
+ event=data["event"],
333
+ nodeId=data["nodeId"],
334
+ progress=data["progress"],
335
+ )
336
+
210
337
 
211
338
  NODE_EVENT_MODEL_MAP: dict[str, type[BaseNodeEventModel]] = {
212
339
  "alive": AliveEventModel,
@@ -213,7 +213,11 @@ class NodeFirmwareUpdateFileInfo:
213
213
  cls, data: NodeFirmwareUpdateFileInfoDataType
214
214
  ) -> NodeFirmwareUpdateFileInfo:
215
215
  """Initialize from dict."""
216
- return cls(**data)
216
+ return cls(
217
+ target=data["target"],
218
+ url=data["url"],
219
+ integrity=data["integrity"],
220
+ )
217
221
 
218
222
  def to_dict(self) -> NodeFirmwareUpdateFileInfoDataType:
219
223
  """Return dict representation of the object."""
@@ -8,7 +8,6 @@ from typing import TYPE_CHECKING, Any, TypedDict
8
8
 
9
9
  from ..const import (
10
10
  VALUE_UNKNOWN,
11
- CommandClass,
12
11
  CommandStatus,
13
12
  ConfigurationValueType,
14
13
  SetValueStatus,
@@ -75,13 +74,6 @@ class ValueDataType(TypedDict, total=False):
75
74
  ccVersion: int # required
76
75
 
77
76
 
78
- def _init_value(node: Node, val: ValueDataType) -> Value | ConfigurationValue:
79
- """Initialize a Value object from ValueDataType."""
80
- if val["commandClass"] == CommandClass.CONFIGURATION:
81
- return ConfigurationValue(node, val)
82
- return Value(node, val)
83
-
84
-
85
77
  def _get_value_id_str_from_dict(node: Node, val: ValueDataType) -> str:
86
78
  """Return string ID of value from ValueDataType dict."""
87
79
  return get_value_id_str(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zwave-js-server-python
3
- Version: 0.56.0
3
+ Version: 0.58.0
4
4
  Summary: Python wrapper for zwave-js-server
5
5
  Author-email: Home Assistant Team <hello@home-assistant.io>
6
6
  License: Apache License
@@ -212,9 +212,9 @@ Classifier: Development Status :: 4 - Beta
212
212
  Classifier: Intended Audience :: Developers
213
213
  Classifier: Natural Language :: English
214
214
  Classifier: Programming Language :: Python :: 3
215
- Classifier: Programming Language :: Python :: 3.11
215
+ Classifier: Programming Language :: Python :: 3.12
216
216
  Classifier: Topic :: Home Automation
217
- Requires-Python: >=3.11
217
+ Requires-Python: >=3.12
218
218
  Description-Content-Type: text/markdown
219
219
  License-File: LICENSE
220
220
  Requires-Dist: aiohttp >3
@@ -2,12 +2,12 @@ zwave_js_server/__init__.py,sha256=Ey3O4Tha56uU-M92oLJmQHupCJ7B9oZmxlQTo8pGUM8,4
2
2
  zwave_js_server/__main__.py,sha256=X6Zdbtv6QmYjsWeQ5OvtIRhtEyT1o3o0XvAmXtRrgoY,3659
3
3
  zwave_js_server/client.py,sha256=i9TaYZ8SArj1P1Z2HeAFnKr43dmXYXPJmPVFNxQ8ZIw,19829
4
4
  zwave_js_server/dump.py,sha256=ZBhkC07ndrFd784zpogfjRJtAdEh8-y8ZycvrGf34sE,1523
5
- zwave_js_server/event.py,sha256=EgNBgCNqPpRIL3zPQnRcPSfotdM-naYTqBH4r1gF4MM,2197
5
+ zwave_js_server/event.py,sha256=xsF_4mCVMWpEiVV-LNCST9kSqNt3hni4EV3ZT7qrQrw,2403
6
6
  zwave_js_server/exceptions.py,sha256=8SY6FA8NiTEQgtauLR83F7m69gBGQviJ6O2obirH2po,6148
7
7
  zwave_js_server/firmware.py,sha256=KXB_-MgBDlNg289bPibUeWtF4l8WtEq9jmiFFMYg1KM,2381
8
8
  zwave_js_server/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  zwave_js_server/version.py,sha256=PUwxOVcUMk5pOguQP9zAjiPjs1Nnmiwj3fcA4HJLiBg,401
10
- zwave_js_server/const/__init__.py,sha256=I43CH0L33AQUFVVDh48FDO6sIt-aZBtRALQHgauPBRE,13808
10
+ zwave_js_server/const/__init__.py,sha256=EFn6K6Pq2LG-iO0UWb0mm1SaZ5EbEm1j7BQvL3R-jek,14263
11
11
  zwave_js_server/const/command_class/__init__.py,sha256=WilOppnr9CXahDjEEkAXyh_j7iCq_qZ1GtBkjWLoQUg,37
12
12
  zwave_js_server/const/command_class/barrier_operator.py,sha256=IJ195hGKEi1FLLqKWMtC2ZhY9Jt5PACr7GYTyVPjkKM,820
13
13
  zwave_js_server/const/command_class/basic.py,sha256=cs0k7p5qxrwpR8-NvXQLtnfEsC6IlBAYiW79DaM_6Eg,96
@@ -16,8 +16,8 @@ zwave_js_server/const/command_class/color_switch.py,sha256=tuKpgZSERdcVxo48YheeR
16
16
  zwave_js_server/const/command_class/energy_production.py,sha256=Ah9Zzb3EHFrN28v-DrblXVS9I40VnhO57fLyq-d-zBk,1501
17
17
  zwave_js_server/const/command_class/entry_control.py,sha256=WetdiEx0K4QaasYS1wEYndxz5lFqpvVcLR5Slz03T1s,972
18
18
  zwave_js_server/const/command_class/humidity_control.py,sha256=AtrhAaDst7LC7c-PZeLmdgoo5D6996PfwuJrdni-yr8,1894
19
- zwave_js_server/const/command_class/lock.py,sha256=HTLnjVYrLnGbWhrvETeaCbHXKemklDfzOHsD4D0uHh4,6629
20
- zwave_js_server/const/command_class/meter.py,sha256=l_ys_r5lOGGxW-XfdgSobS3QxPsaVp3hV8Jm9dl3a_A,3998
19
+ zwave_js_server/const/command_class/lock.py,sha256=0HtTwW6ifAeCk3FhupCXRIKOvvay_w1Lc6w83FACZtY,6706
20
+ zwave_js_server/const/command_class/meter.py,sha256=OY5QeAViJnlwjLeDO-_CgTi9JD5r0hpu8ofMbuc2iyw,4070
21
21
  zwave_js_server/const/command_class/multilevel_sensor.py,sha256=Js5ZIORRkGAEfJa491m91Jf8L0Owxg9ibUBQTSaUSP4,37067
22
22
  zwave_js_server/const/command_class/multilevel_switch.py,sha256=yBDE9O9Ad1eMK_rgqs7l-DPJxnB-fi9CGclgpFc-QRk,576
23
23
  zwave_js_server/const/command_class/notification.py,sha256=psLLSYNsBaKq3lEOTXdChvLrNPwZK2CD3BCGWmD1QGs,37899
@@ -29,11 +29,11 @@ zwave_js_server/const/command_class/thermostat.py,sha256=VqgKCF_Itfdq29cCzA0hN_K
29
29
  zwave_js_server/const/command_class/wake_up.py,sha256=Rvnr1-_BPmWe8-dxpBoqEMo9feew5imdtZar5a9C9H8,175
30
30
  zwave_js_server/const/command_class/window_covering.py,sha256=o2_CBQ5DSbDNmJQxrcCH8pUXPNGMyGZTtlgUA-7SbYE,2088
31
31
  zwave_js_server/model/__init__.py,sha256=XfyKH8lxZ3CB7CbRkOr5sR-eV0GrklZiBtNPmlnCJ_8,123
32
- zwave_js_server/model/association.py,sha256=nRFEC2ysQlIq3Xezh9Hqx9BTdL0b5PNDN7XguIKhhvU,527
33
- zwave_js_server/model/command_class.py,sha256=_YimyLtb3aFHdhbYURNZZQlAf-lc3CC8HW8Vbk-Vrqc,1263
34
- zwave_js_server/model/device_class.py,sha256=owVKlFjQ32O3qrOiL6QruVKLfzMjS9Id_s-oGInf4eY,1964
32
+ zwave_js_server/model/association.py,sha256=4rpf8PbafCYCfNJGISAmnpfcvJZTo_jPDGm2M-BuiPk,878
33
+ zwave_js_server/model/command_class.py,sha256=SDTyGKlz5tDUoBb4RgKwPGwPuJvZ77a_q2EllN4bnzU,1394
34
+ zwave_js_server/model/device_class.py,sha256=WTeYuR9PoIMzfjNhE21XIlHoTA9yDNEuRPkFS1W6nts,1609
35
35
  zwave_js_server/model/device_config.py,sha256=PV13U1T0zlBJ4CvoLziFW2SUJHHumYiez-n2qOapaQw,6423
36
- zwave_js_server/model/driver.py,sha256=w4PXh90OYSI7hEHA7VjIMYrY-NS-wV32H5u2ykrdTLI,6518
36
+ zwave_js_server/model/driver.py,sha256=6g-8VmrCGLJuPa2O1NNdTaHNMxqMwnXbgzUIhQCRcl8,6779
37
37
  zwave_js_server/model/duration.py,sha256=OW2OqReexL6GXxxLs__i5Vs3JCVoODgLpwPHU48yynU,1153
38
38
  zwave_js_server/model/endpoint.py,sha256=0ZbT3I82xcCH-GRx_6MDgyNJB1bUBpFtSsU0slOpUeM,12609
39
39
  zwave_js_server/model/log_config.py,sha256=uF7gJlr2dSBP2mBMYzOyFiV_T45PwGU98AM5c7qs2g0,1574
@@ -41,19 +41,19 @@ zwave_js_server/model/log_message.py,sha256=SNicnss7LUZd6woMecNQ0ZKwghC9OmxNdA1v
41
41
  zwave_js_server/model/notification.py,sha256=-M9MZ1RUWmUCHuIU_So6h5sYhMILKxntGx3zBkKaqeo,6165
42
42
  zwave_js_server/model/statistics.py,sha256=in7S8oxWlG38tCEz1k3lxLjEsfY5yfsnD0bolcEeuHg,3233
43
43
  zwave_js_server/model/utils.py,sha256=VMoJQ99QRkpJleJhXR4eojbgObdZZeEfse5gonmK7Ic,1157
44
- zwave_js_server/model/value.py,sha256=7vr5CYV2TC5I593ww1CBJvM1GzpTFM31qfkYZto6_K0,13552
44
+ zwave_js_server/model/value.py,sha256=Ku_VnX79WL82SD6Up01qQUNRldnCvi37HeEuTrTdBPU,13266
45
45
  zwave_js_server/model/version.py,sha256=EnyL6O8r2gSv7qLIuZ-sWnybG5JnJWw-IEE5UtIUjiM,1272
46
- zwave_js_server/model/controller/__init__.py,sha256=HkVk2on8qljAvYw7jcSHv2p1lIs0UDD1QDu20J4SRdo,36544
46
+ zwave_js_server/model/controller/__init__.py,sha256=MMABFVu7GG1rYywM01gHWokGBpcwI1i-DmTunT20TBo,36653
47
47
  zwave_js_server/model/controller/data_model.py,sha256=5e6M0t7RkSJytovmDz1tULMFFoCQ1TsGHe56scrZRqI,851
48
- zwave_js_server/model/controller/event_model.py,sha256=-pqe316I7MVdIm8btovsw5ZXZbillDyH7AnGoYtvZWg,6207
48
+ zwave_js_server/model/controller/event_model.py,sha256=FUU9PzVUO9ouOVldzKmBndBI4I3Z9Dv2cPnGFT0Yt-c,10172
49
49
  zwave_js_server/model/controller/firmware.py,sha256=GnctTeLitmUVf3wfJgZsDBAlQP4eDU6ytohXqigjGEg,2907
50
- zwave_js_server/model/controller/inclusion_and_provisioning.py,sha256=Vq8uDujGkt_oaPKV4F8RdcM1eCCJKBSvbYlnI0qHYK8,7491
50
+ zwave_js_server/model/controller/inclusion_and_provisioning.py,sha256=PAO5HQE_yyTMxoVN3Woth1qC_oL6EzJNJ7NEvMtpBEA,7667
51
51
  zwave_js_server/model/controller/rebuild_routes.py,sha256=ElAZdSLiDaQLbGgfJQMnuilTpsSbCz3qag3lFBt2JoM,1073
52
52
  zwave_js_server/model/controller/statistics.py,sha256=iU2wiRvWvHzYGwydOqs8Y7CBdKA3DgL6tI1NW1zBTfU,4672
53
- zwave_js_server/model/node/__init__.py,sha256=N3fBQImgnNzCDVsmc3NnTApZV8lirusdn-SNoJcAHNY,40911
53
+ zwave_js_server/model/node/__init__.py,sha256=6YZd1Xo-ZNrd2AB0OgY2X3VWJNQLl4E6NAzNvX0THAo,41118
54
54
  zwave_js_server/model/node/data_model.py,sha256=sQp0Mlp0SBkPv170cD0MjIX4BAMmrr4HtTZaKbIA0kQ,1845
55
- zwave_js_server/model/node/event_model.py,sha256=Xaw_P3IlefSA-sFCJSJE4qmYeptQGSuYHNlnYPJlImg,6281
56
- zwave_js_server/model/node/firmware.py,sha256=rPWNYSxHpxviZ2272r_FY8WdAv-qMurXNOsFlAyZDuA,10106
55
+ zwave_js_server/model/node/event_model.py,sha256=mSRqCIBt6LXvCmMaOGmWz_cLrfPqot_ScZLmVr_z2w4,10055
56
+ zwave_js_server/model/node/firmware.py,sha256=jF1CrI6hnETj8oZsXuwQVnIkTJ9qQ8uJEdY7JAthpC0,10214
57
57
  zwave_js_server/model/node/health_check.py,sha256=GuDFPfk5BL7aK4q5aEtGcpyZz_F-aLEIGeVw_4shq5E,5341
58
58
  zwave_js_server/model/node/statistics.py,sha256=f8JElpXEtT7y9cLhH6UhOGVwrGprtfL5GQX1VIKAGcQ,2871
59
59
  zwave_js_server/util/__init__.py,sha256=ArF1K885aW0GdVd7Lo8fl8Atf70gvsxO5Ra_WoJTG28,42
@@ -65,9 +65,9 @@ zwave_js_server/util/command_class/__init__.py,sha256=sRxti47ekLTzfk8B609CMQumIb
65
65
  zwave_js_server/util/command_class/energy_production.py,sha256=K1VmGDlqXmKDfQRpTu5o99sjnDShBMV_crEb49o-O_4,1489
66
66
  zwave_js_server/util/command_class/meter.py,sha256=tJ7rbwWUZbJCS7xEJWS_KnqUUGR8RN0f2S8iLkufae0,1258
67
67
  zwave_js_server/util/command_class/multilevel_sensor.py,sha256=wG4GQ0kjrP6d3x5DpEkUHrZd8-0LbvXoYdIxZAf6bso,1427
68
- zwave_js_server_python-0.56.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
69
- zwave_js_server_python-0.56.0.dist-info/METADATA,sha256=HBXTuqRHL0PW8e7p55c4cuZeCdGDZkBgv2U_EWOxdxc,14767
70
- zwave_js_server_python-0.56.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
71
- zwave_js_server_python-0.56.0.dist-info/entry_points.txt,sha256=lvzma7Rd_3FW_k-_xGuTfpvcvA2MR_22DOz5f1t7-xg,73
72
- zwave_js_server_python-0.56.0.dist-info/top_level.txt,sha256=-hwsl-i4Av5Op_yfOHC_OP56KPmzp_iVEkeohRIN5Ng,16
73
- zwave_js_server_python-0.56.0.dist-info/RECORD,,
68
+ zwave_js_server_python-0.58.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
69
+ zwave_js_server_python-0.58.0.dist-info/METADATA,sha256=Al2giY0YNUq8pRiPN2g9o74p7-o1JSV5KfcI30UDaRA,14767
70
+ zwave_js_server_python-0.58.0.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
71
+ zwave_js_server_python-0.58.0.dist-info/entry_points.txt,sha256=lvzma7Rd_3FW_k-_xGuTfpvcvA2MR_22DOz5f1t7-xg,73
72
+ zwave_js_server_python-0.58.0.dist-info/top_level.txt,sha256=-hwsl-i4Av5Op_yfOHC_OP56KPmzp_iVEkeohRIN5Ng,16
73
+ zwave_js_server_python-0.58.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (74.1.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5