zwave-js-server-python 0.56.0__py3-none-any.whl → 0.58.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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