zwave-js-server-python 0.37.2__py3-none-any.whl → 0.38.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.
@@ -3,14 +3,15 @@ import sys
3
3
  from enum import Enum, IntEnum
4
4
 
5
5
  # minimal server schema version we can handle
6
- MIN_SERVER_SCHEMA_VERSION = 17
6
+ MIN_SERVER_SCHEMA_VERSION = 18
7
7
  # max server schema version we can handle (and our code is compatible with)
8
- MAX_SERVER_SCHEMA_VERSION = 17
8
+ MAX_SERVER_SCHEMA_VERSION = 18
9
9
 
10
10
  TYPING_EXTENSION_FOR_TYPEDDICT_REQUIRED = sys.version_info < (3, 9, 2)
11
11
 
12
12
  VALUE_UNKNOWN = "unknown"
13
13
 
14
+ NOT_INTERVIEWED = "None"
14
15
  INTERVIEW_FAILED = "Failed"
15
16
 
16
17
  CURRENT_STATE_PROPERTY = "currentState"
@@ -16,6 +16,7 @@ async def begin_firmware_update(
16
16
  file: bytes,
17
17
  session: aiohttp.ClientSession,
18
18
  file_format: Optional[str] = None,
19
+ target: Optional[int] = None,
19
20
  ) -> None:
20
21
  """Send beginFirmwareUpdate command to Node."""
21
22
  client = Client(url, session)
@@ -33,7 +34,10 @@ async def begin_firmware_update(
33
34
  if file_format is not None:
34
35
  cmd["firmwareFileFormat"] = file_format
35
36
 
36
- await client.async_send_command(cmd, require_schema=5)
37
+ if target is not None:
38
+ cmd["target"] = target
39
+
40
+ await client.async_send_command(cmd, require_schema=18)
37
41
  await client.disconnect()
38
42
  if not receive_task.done():
39
43
  receive_task.cancel()
@@ -733,6 +733,9 @@ class Controller(EventBase):
733
733
  def handle_exclusion_stopped(self, event: Event) -> None:
734
734
  """Process an exclusion stopped event."""
735
735
 
736
+ def handle_node_found(self, event: Event) -> None:
737
+ """Process a node found event."""
738
+
736
739
  def handle_node_added(self, event: Event) -> None:
737
740
  """Process a node added event."""
738
741
  node = event.data["node"] = Node(self.client, event.data["node"])
@@ -97,6 +97,13 @@ class NodeAddedEventModel(BaseControllerEventModel):
97
97
  result: InclusionResultDataType
98
98
 
99
99
 
100
+ class NodeFoundEventModel(BaseControllerEventModel):
101
+ """Model for `node found` event data."""
102
+
103
+ event: Literal["node found"]
104
+ node: NodeDataType
105
+
106
+
100
107
  class NodeRemovedEventModel(BaseControllerEventModel):
101
108
  """Model for `node removed` event data."""
102
109
 
@@ -158,6 +165,7 @@ CONTROLLER_EVENT_MODEL_MAP: Dict[str, Type["BaseControllerEventModel"]] = {
158
165
  "inclusion started": InclusionStartedEventModel,
159
166
  "inclusion stopped": InclusionStoppedEventModel,
160
167
  "node added": NodeAddedEventModel,
168
+ "node found": NodeFoundEventModel,
161
169
  "node removed": NodeRemovedEventModel,
162
170
  "nvm backup progress": NVMBackupProgressEventModel,
163
171
  "nvm convert progress": NVMConvertProgressEventModel,
@@ -1,8 +1,8 @@
1
1
  """Provide a model for Z-Wave firmware."""
2
2
  from enum import IntEnum
3
- from typing import TYPE_CHECKING, Optional
3
+ from typing import TYPE_CHECKING, List, Optional, Union
4
4
 
5
- from ..const import TYPING_EXTENSION_FOR_TYPEDDICT_REQUIRED
5
+ from ..const import TYPING_EXTENSION_FOR_TYPEDDICT_REQUIRED, VALUE_UNKNOWN
6
6
 
7
7
  if TYPING_EXTENSION_FOR_TYPEDDICT_REQUIRED:
8
8
  from typing_extensions import TypedDict
@@ -13,6 +13,75 @@ if TYPE_CHECKING:
13
13
  from .node import Node
14
14
 
15
15
 
16
+ class FirmwareUpdateCapabilitiesDataType(TypedDict, total=False):
17
+ """Represent a firmware update capabilities dict type."""
18
+
19
+ firmwareUpgradable: bool # required
20
+ firmwareTargets: List[int]
21
+ continuesToFunction: Union[bool, str]
22
+ supportsActivation: Union[bool, str]
23
+
24
+
25
+ class FirmwareUpdateCapabilitiesDict(TypedDict, total=False):
26
+ """Represent a dict from FirmwareUpdateCapabilities."""
27
+
28
+ firmware_upgradable: bool # required
29
+ firmware_targets: List[int]
30
+ continues_to_function: Optional[bool]
31
+ supports_activation: Optional[bool]
32
+
33
+
34
+ class FirmwareUpdateCapabilities:
35
+ """Model for firmware update capabilities."""
36
+
37
+ def __init__(self, data: FirmwareUpdateCapabilitiesDataType) -> None:
38
+ """Initialize class."""
39
+ self.data = data
40
+
41
+ @property
42
+ def firmware_upgradable(self) -> bool:
43
+ """Return whether firmware is upgradable."""
44
+ return self.data["firmwareUpgradable"]
45
+
46
+ @property
47
+ def firmware_targets(self) -> List[int]:
48
+ """Return firmware targets."""
49
+ if not self.firmware_upgradable:
50
+ raise TypeError("Firmware is not upgradeable.")
51
+ return self.data["firmwareTargets"]
52
+
53
+ @property
54
+ def continues_to_function(self) -> Optional[bool]:
55
+ """Return whether node continues to function during update."""
56
+ if not self.firmware_upgradable:
57
+ raise TypeError("Firmware is not upgradeable.")
58
+ if (val := self.data["continuesToFunction"]) == VALUE_UNKNOWN:
59
+ return None
60
+ assert isinstance(val, bool)
61
+ return val
62
+
63
+ @property
64
+ def supports_activation(self) -> Optional[bool]:
65
+ """Return whether node supports delayed activation of the new firmware."""
66
+ if not self.firmware_upgradable:
67
+ raise TypeError("Firmware is not upgradeable.")
68
+ if (val := self.data["supportsActivation"]) == VALUE_UNKNOWN:
69
+ return None
70
+ assert isinstance(val, bool)
71
+ return val
72
+
73
+ def to_dict(self) -> FirmwareUpdateCapabilitiesDict:
74
+ """Return dict representation of the object."""
75
+ if not self.firmware_upgradable:
76
+ return {"firmware_upgradable": self.firmware_upgradable}
77
+ return {
78
+ "firmware_upgradable": self.firmware_upgradable,
79
+ "firmware_targets": self.firmware_targets,
80
+ "continues_to_function": self.continues_to_function,
81
+ "supports_activation": self.supports_activation,
82
+ }
83
+
84
+
16
85
  class FirmwareUpdateStatus(IntEnum):
17
86
  """Enum with all Firmware update status values.
18
87
 
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, cast
4
4
 
5
5
  from ...const import (
6
6
  INTERVIEW_FAILED,
7
+ NOT_INTERVIEWED,
7
8
  CommandClass,
8
9
  NodeStatus,
9
10
  PowerLevel,
@@ -21,6 +22,8 @@ from ..device_class import DeviceClass
21
22
  from ..device_config import DeviceConfig
22
23
  from ..endpoint import Endpoint
23
24
  from ..firmware import (
25
+ FirmwareUpdateCapabilities,
26
+ FirmwareUpdateCapabilitiesDataType,
24
27
  FirmwareUpdateFinished,
25
28
  FirmwareUpdateFinishedDataType,
26
29
  FirmwareUpdateProgress,
@@ -269,7 +272,16 @@ class Node(EventBase):
269
272
  @property
270
273
  def in_interview(self) -> bool:
271
274
  """Return whether node is currently being interviewed."""
272
- return not self.ready and self.interview_stage != INTERVIEW_FAILED
275
+ return (
276
+ not self.ready
277
+ and not self.awaiting_manual_interview
278
+ and self.interview_stage != INTERVIEW_FAILED
279
+ )
280
+
281
+ @property
282
+ def awaiting_manual_interview(self) -> bool:
283
+ """Return whether node requires a manual interview."""
284
+ return self.interview_stage in (None, NOT_INTERVIEWED)
273
285
 
274
286
  @property
275
287
  def command_classes(self) -> List[CommandClassInfo]:
@@ -496,9 +508,23 @@ class Node(EventBase):
496
508
  )
497
509
  return ValueMetadata(cast(MetaDataType, data))
498
510
 
511
+ async def async_get_firmware_update_capabilities(
512
+ self,
513
+ ) -> FirmwareUpdateCapabilities:
514
+ """Send getFirmwareUpdateCapabilities command to Node."""
515
+ data = await self.async_send_command(
516
+ "get_firmware_update_capabilities",
517
+ require_schema=7,
518
+ wait_for_result=True,
519
+ )
520
+ assert data
521
+ return FirmwareUpdateCapabilities(
522
+ cast(FirmwareUpdateCapabilitiesDataType, data["capabilities"])
523
+ )
524
+
499
525
  async def async_abort_firmware_update(self) -> None:
500
526
  """Send abortFirmwareUpdate command to Node."""
501
- await self.async_send_command("abort_firmware_update", wait_for_result=False)
527
+ await self.async_send_command("abort_firmware_update", wait_for_result=True)
502
528
 
503
529
  async def async_poll_value(self, val: Union[Value, str]) -> None:
504
530
  """Send pollValue command to Node for given value (or value_id)."""
@@ -644,6 +670,18 @@ class Node(EventBase):
644
670
  )
645
671
  self.data["location"] = location
646
672
 
673
+ async def async_get_firmware_update_progress(self) -> bool:
674
+ """
675
+ Send getFirmwareUpdateProgress command to Node.
676
+
677
+ If `True`, a firmware update for this node is in progress.
678
+ """
679
+ data = await self.async_send_command(
680
+ "get_firmware_update_progress", require_schema=18, wait_for_result=True
681
+ )
682
+ assert data
683
+ return cast(bool, data["progress"])
684
+
647
685
  async def async_set_keep_awake(self, keep_awake: bool) -> None:
648
686
  """Set node keep awake state."""
649
687
  await self.async_send_command(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zwave-js-server-python
3
- Version: 0.37.2
3
+ Version: 0.38.0
4
4
  Summary: Python wrapper for zwave-js-server
5
5
  Home-page: https://github.com/home-assistant-libs/zwave-js-server-python
6
6
  Author: Home Assistant Team
@@ -4,10 +4,10 @@ zwave_js_server/client.py,sha256=Fu_QlYYo-HrpENdcUxFDsSQmEQBxW6kA3_JAYo8LPgs,149
4
4
  zwave_js_server/dump.py,sha256=hTyeW8fPleyQyYyPjFeR_JxwmFRHvtpmpn1L9uNpfiw,1213
5
5
  zwave_js_server/event.py,sha256=E2bIEb635al9MsCB5rkk3ZklU4-YkmqmXtifzlbxXaQ,1958
6
6
  zwave_js_server/exceptions.py,sha256=guJlsUNQMGl-P8dVydup686_xzpbzCkd1870RbqZ6PE,5623
7
- zwave_js_server/firmware.py,sha256=40kf1yTcZjoO8oiQ5HdXG1sGt-g-cbEJcJQfRrLLbdc,1045
7
+ zwave_js_server/firmware.py,sha256=Wo_o2e_jHeuX0mDTFUEJ-l_m3QOkXIwVFsLxBLYAC8E,1139
8
8
  zwave_js_server/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  zwave_js_server/version.py,sha256=RDFP2kSU3cCVIQbgMWggdeDnvhtVsZzzZg9pOjH7CC8,364
10
- zwave_js_server/const/__init__.py,sha256=FnImJja993dn8Hdrss29P5eq6oGoMZ0ZYu3QGidVU68,8481
10
+ zwave_js_server/const/__init__.py,sha256=hmYMLOcJKwHOOqXYF7N7lNMvA8dl9L4YFnkvApcFKlI,8506
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=NBhTp5T-6T31glpIKrEOLgbKTndkB5gqdQmCJlXFFUA,783
13
13
  zwave_js_server/const/command_class/color_switch.py,sha256=9jIDdmz8gJ5d1RdINHiK7Yh0NXg1I0U1xVzkrQJICk8,918
@@ -30,7 +30,7 @@ zwave_js_server/model/device_class.py,sha256=KpSM101bGa_3Mig4C-_rkE4CzqImK2JPIUt
30
30
  zwave_js_server/model/device_config.py,sha256=7NaMa4BZ5tGe2p0YtOQFIUjBwRVF7GYWVExLwAgIUtE,6659
31
31
  zwave_js_server/model/driver.py,sha256=u5jOFZ2-mRWqAbiNB5yX_3qC7Uw1mjJdxLgeNignnho,6289
32
32
  zwave_js_server/model/endpoint.py,sha256=YGZts5-5y1ok6gIi7NsjM8puLwpv4XDVJhfUUTJ4rJQ,6001
33
- zwave_js_server/model/firmware.py,sha256=0AlV2mbjlmejV1eh0oHCUU-2Ysyec9a0X9BTvHG3wYs,2493
33
+ zwave_js_server/model/firmware.py,sha256=-ercachu45pHd8cafzhDey5XpxX4b0CCufSFistJQYQ,4996
34
34
  zwave_js_server/model/log_config.py,sha256=F-QM7oHUXAfAxbdkrvmi6k6woM4VOwxB3qRrGmTQiQA,1722
35
35
  zwave_js_server/model/log_message.py,sha256=IxZ4USpXTeHsuRNS61NDPYMSIflv1KDO_EjUy4_vavE,5859
36
36
  zwave_js_server/model/notification.py,sha256=yLTUgOa_N0wedIsuJNDdhXEbfPVSIdXof7h_A_aibEU,6706
@@ -38,12 +38,12 @@ zwave_js_server/model/statistics.py,sha256=uG87o-iNGKHxJc4Kfr2ZJ0VY7NjCbdxwgWOqu
38
38
  zwave_js_server/model/utils.py,sha256=fLs1pOKG53yWQggBWUKvPgzlT0JkK3biLzRkhPBNArI,814
39
39
  zwave_js_server/model/value.py,sha256=dV6a3QMga1T-KfCQsle6lauK9rxSzd6rhF-eldRaJOU,8754
40
40
  zwave_js_server/model/version.py,sha256=W1H-UbhKdgMW5KdnY9MUfRFibfMZSOD3nljXOv1ZVVM,1398
41
- zwave_js_server/model/controller/__init__.py,sha256=d7T0W66vERzugpLn1Qxt8mG5CU4BGIuj8D_AOB3pKgc,29677
41
+ zwave_js_server/model/controller/__init__.py,sha256=L4tBNDlocsQy3Xbi1u51IyZqUt99URrXG5oD8BHCBFs,29775
42
42
  zwave_js_server/model/controller/data_model.py,sha256=On7ZCEe5-vbVPs_ucFqlquxpjilT2TDGtiZwE8odtV4,970
43
- zwave_js_server/model/controller/event_model.py,sha256=a_YtQFyEbDs9nDX12GnTLiiKsJai5gUOq4RlENLa4eY,4941
43
+ zwave_js_server/model/controller/event_model.py,sha256=PseC6YMT4NSRovUKbdYy_lZtB0qe1ujspK3W7miJ1rU,5137
44
44
  zwave_js_server/model/controller/inclusion_and_provisioning.py,sha256=01YUq4YBhQe3gmJAIsN6ctMM3pcLEaGMSyIySBI9v2c,7497
45
45
  zwave_js_server/model/controller/statistics.py,sha256=7aeFjKq_-TvcHBWc-a4xQP6wvO3GoGjr9P-m8uyOco8,4031
46
- zwave_js_server/model/node/__init__.py,sha256=Q4QWFL908uyKQLvEeEjhIlOUfZjomLSfIJeVt02Om60,29290
46
+ zwave_js_server/model/node/__init__.py,sha256=69UwPFVPApQ8uxknIoYvOkf-FU0c5B2kOLomXSp1GaI,30564
47
47
  zwave_js_server/model/node/data_model.py,sha256=Zdl68Oa9vUn2wegriFOcU70Q2yJO41rGKpdAdIbbtAU,1730
48
48
  zwave_js_server/model/node/event_model.py,sha256=kY-HxdRpJUGiQaM4T7DInQBJ4rf4pw1JY-nImsF-1kY,6055
49
49
  zwave_js_server/model/node/health_check.py,sha256=EAOMBkMKd5q--fhax2GvJhWdhuuv5dX_-2Hf_mczODs,6054
@@ -56,9 +56,9 @@ zwave_js_server/util/node.py,sha256=KUg-Z-7hdDLGKKCYLktc4oOgiPbDT7ZUYqUH_IPLwO4,
56
56
  zwave_js_server/util/command_class/__init__.py,sha256=sRxti47ekLTzfk8B609CMQumIbcD6mon2ZS0zwh9omY,59
57
57
  zwave_js_server/util/command_class/meter.py,sha256=Qkif1ul4KpV_k6Dc7yNXlSjlJLLTH8mCitgQk9J9W0A,1277
58
58
  zwave_js_server/util/command_class/multilevel_sensor.py,sha256=p92YLNRze5z3UWhfIDJO95F-j5tqx1PKUG9oamo9Dng,1446
59
- zwave_js_server_python-0.37.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
60
- zwave_js_server_python-0.37.2.dist-info/METADATA,sha256=XhLZxR5yeoqXZvMi7z7ODiKpQw6uIu_8_ZWieNs1xw4,1712
61
- zwave_js_server_python-0.37.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
62
- zwave_js_server_python-0.37.2.dist-info/entry_points.txt,sha256=_8Swg1yhKiBElo6k1fxIEd6E8uPz8PDxQpwQoZ29FZE,74
63
- zwave_js_server_python-0.37.2.dist-info/top_level.txt,sha256=-hwsl-i4Av5Op_yfOHC_OP56KPmzp_iVEkeohRIN5Ng,16
64
- zwave_js_server_python-0.37.2.dist-info/RECORD,,
59
+ zwave_js_server_python-0.38.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
60
+ zwave_js_server_python-0.38.0.dist-info/METADATA,sha256=oIWlUj5T-6dPuxhpqQJa59Y6WqFekvIeCn5exT2PRLk,1712
61
+ zwave_js_server_python-0.38.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
62
+ zwave_js_server_python-0.38.0.dist-info/entry_points.txt,sha256=_8Swg1yhKiBElo6k1fxIEd6E8uPz8PDxQpwQoZ29FZE,74
63
+ zwave_js_server_python-0.38.0.dist-info/top_level.txt,sha256=-hwsl-i4Av5Op_yfOHC_OP56KPmzp_iVEkeohRIN5Ng,16
64
+ zwave_js_server_python-0.38.0.dist-info/RECORD,,