zwave-js-server-python 0.35.2__py3-none-any.whl → 0.35.3__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.
@@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Optional
4
4
  from .const import CommandClass
5
5
 
6
6
  if TYPE_CHECKING:
7
- from .event import Event
8
7
  from .model.value import Value
9
8
 
10
9
 
@@ -157,16 +156,3 @@ class UnknownValueData(BaseZwaveJSServerError):
157
156
  "upstream issue with the driver or missing support for this data in the "
158
157
  "library"
159
158
  )
160
-
161
-
162
- class NotificationHasUnsupportedCommandClass(BaseZwaveJSServerError):
163
- """Exception raised when notification is received for an unsupported CC."""
164
-
165
- def __init__(self, event: "Event", command_class: CommandClass) -> None:
166
- """Initialize an invalid Command Class error."""
167
- self.event_data = event.data
168
- self.command_class = command_class
169
- super().__init__(
170
- "Notification received with unsupported command class "
171
- f"{command_class.name}: {event.data}"
172
- )
@@ -16,7 +16,7 @@ class AssociationGroup:
16
16
 
17
17
 
18
18
  @dataclass
19
- class Association:
19
+ class AssociationAddress:
20
20
  """Represent a association dict type."""
21
21
 
22
22
  node_id: int
@@ -12,7 +12,7 @@ from ...const import (
12
12
  )
13
13
  from ...event import Event, EventBase
14
14
  from ...util.helpers import convert_base64_to_bytes, convert_bytes_to_base64
15
- from ..association import Association, AssociationGroup
15
+ from ..association import AssociationAddress, AssociationGroup
16
16
  from ..node import Node
17
17
  from .data_model import ControllerDataType
18
18
  from .event_model import CONTROLLER_EVENT_MODEL_MAP
@@ -420,18 +420,21 @@ class Controller(EventBase):
420
420
  return cast(bool, data["failed"])
421
421
 
422
422
  async def async_get_association_groups(
423
- self, node_id: int
423
+ self, source: AssociationAddress
424
424
  ) -> Dict[int, AssociationGroup]:
425
425
  """Send getAssociationGroups command to Controller."""
426
+ source_data = {"nodeId": source.node_id}
427
+ if source.endpoint is not None:
428
+ source_data["endpoint"] = source.endpoint
426
429
  data = await self.client.async_send_command(
427
430
  {
428
431
  "command": "controller.get_association_groups",
429
- "nodeId": node_id,
432
+ **source_data,
430
433
  }
431
434
  )
432
435
  groups = {}
433
436
  for key, group in data["groups"].items():
434
- groups[key] = AssociationGroup(
437
+ groups[int(key)] = AssociationGroup(
435
438
  max_nodes=group["maxNodes"],
436
439
  is_lifeline=group["isLifeline"],
437
440
  multi_channel=group["multiChannel"],
@@ -441,84 +444,125 @@ class Controller(EventBase):
441
444
  )
442
445
  return groups
443
446
 
444
- async def async_get_associations(self, node_id: int) -> Dict[int, Association]:
447
+ async def async_get_associations(
448
+ self, source: AssociationAddress
449
+ ) -> Dict[int, List[AssociationAddress]]:
445
450
  """Send getAssociations command to Controller."""
451
+ source_data = {"nodeId": source.node_id}
452
+ if source.endpoint is not None:
453
+ source_data["endpoint"] = source.endpoint
446
454
  data = await self.client.async_send_command(
447
455
  {
448
456
  "command": "controller.get_associations",
449
- "nodeId": node_id,
457
+ **source_data,
450
458
  }
451
459
  )
452
460
  associations = {}
453
- for key, association in data["associations"].items():
454
- associations[key] = Association(
455
- node_id=association["nodeId"], endpoint=association.get("endpoint")
456
- )
461
+ for key, association_addresses in data["associations"].items():
462
+ associations[int(key)] = [
463
+ AssociationAddress(
464
+ node_id=association_address["nodeId"],
465
+ endpoint=association_address.get("endpoint"),
466
+ )
467
+ for association_address in association_addresses
468
+ ]
457
469
  return associations
458
470
 
459
471
  async def async_is_association_allowed(
460
- self, node_id: int, group: int, association: Association
472
+ self, source: AssociationAddress, group: int, association: AssociationAddress
461
473
  ) -> bool:
462
474
  """Send isAssociationAllowed command to Controller."""
475
+ source_data = {"nodeId": source.node_id}
476
+ if source.endpoint is not None:
477
+ source_data["endpoint"] = source.endpoint
478
+
479
+ association_data = {"nodeId": association.node_id}
480
+ if association.endpoint is not None:
481
+ association_data["endpoint"] = association.endpoint
463
482
  data = await self.client.async_send_command(
464
483
  {
465
484
  "command": "controller.is_association_allowed",
466
- "nodeId": node_id,
485
+ **source_data,
467
486
  "group": group,
468
- "association": {
469
- "nodeId": association.node_id,
470
- "endpoint": association.endpoint,
471
- },
487
+ "association": association_data,
472
488
  }
473
489
  )
474
490
  return cast(bool, data["allowed"])
475
491
 
476
492
  async def async_add_associations(
477
- self, node_id: int, group: int, associations: List[Association]
493
+ self,
494
+ source: AssociationAddress,
495
+ group: int,
496
+ associations: List[AssociationAddress],
497
+ wait_for_result: bool = False,
478
498
  ) -> None:
479
499
  """Send addAssociations command to Controller."""
480
- await self.client.async_send_command(
481
- {
482
- "command": "controller.add_associations",
483
- "nodeId": node_id,
484
- "group": group,
485
- "associations": [
486
- {
487
- "nodeId": association.node_id,
488
- "endpoint": association.endpoint,
489
- }
490
- for association in associations
491
- ],
492
- }
493
- )
500
+ source_data = {"nodeId": source.node_id}
501
+ if source.endpoint is not None:
502
+ source_data["endpoint"] = source.endpoint
503
+
504
+ associations_data = []
505
+ for association in associations:
506
+ association_data = {"nodeId": association.node_id}
507
+ if association.endpoint is not None:
508
+ association_data["endpoint"] = association.endpoint
509
+ associations_data.append(association_data)
510
+
511
+ cmd = {
512
+ "command": "controller.add_associations",
513
+ **source_data,
514
+ "group": group,
515
+ "associations": associations_data,
516
+ }
517
+ if wait_for_result:
518
+ await self.client.async_send_command(cmd)
519
+ else:
520
+ await self.client.async_send_command_no_wait(cmd)
494
521
 
495
522
  async def async_remove_associations(
496
- self, node_id: int, group: int, associations: List[Association]
523
+ self,
524
+ source: AssociationAddress,
525
+ group: int,
526
+ associations: List[AssociationAddress],
527
+ wait_for_result: bool = False,
497
528
  ) -> None:
498
529
  """Send removeAssociations command to Controller."""
499
- await self.client.async_send_command(
500
- {
501
- "command": "controller.remove_associations",
502
- "nodeId": node_id,
503
- "group": group,
504
- "associations": [
505
- {
506
- "nodeId": association.node_id,
507
- "endpoint": association.endpoint,
508
- }
509
- for association in associations
510
- ],
511
- }
512
- )
530
+ source_data = {"nodeId": source.node_id}
531
+ if source.endpoint is not None:
532
+ source_data["endpoint"] = source.endpoint
533
+
534
+ associations_data = []
535
+ for association in associations:
536
+ association_data = {"nodeId": association.node_id}
537
+ if association.endpoint is not None:
538
+ association_data["endpoint"] = association.endpoint
539
+ associations_data.append(association_data)
540
+
541
+ cmd = {
542
+ "command": "controller.remove_associations",
543
+ **source_data,
544
+ "group": group,
545
+ "associations": associations_data,
546
+ }
547
+ if wait_for_result:
548
+ await self.client.async_send_command(cmd)
549
+ else:
550
+ await self.client.async_send_command_no_wait(cmd)
513
551
 
514
- async def async_remove_node_from_all_associations(self, node_id: int) -> None:
552
+ async def async_remove_node_from_all_associations(
553
+ self,
554
+ node_id: int,
555
+ wait_for_result: bool = False,
556
+ ) -> None:
515
557
  """Send removeNodeFromAllAssociations command to Controller."""
516
- await self.client.async_send_command(
517
- {
518
- "command": "controller.remove_node_from_all_associations",
519
- "nodeId": node_id,
520
- }
521
- )
558
+ cmd = {
559
+ "command": "controller.remove_node_from_all_associations",
560
+ "nodeId": node_id,
561
+ }
562
+ if wait_for_result:
563
+ await self.client.async_send_command(cmd)
564
+ else:
565
+ await self.client.async_send_command_no_wait(cmd)
522
566
 
523
567
  async def async_get_node_neighbors(self, node_id: int) -> List[int]:
524
568
  """Send getNodeNeighbors command to Controller to get node's neighbors."""
@@ -49,6 +49,24 @@ class Endpoint(EventBase):
49
49
  self.values: Dict[str, Union[ConfigurationValue, Value]] = {}
50
50
  self.update(data, values)
51
51
 
52
+ def __repr__(self) -> str:
53
+ """Return the representation."""
54
+ return f"{type(self).__name__}(node_id={self.node_id}, index={self.index})"
55
+
56
+ def __hash__(self) -> int:
57
+ """Return the hash."""
58
+ return hash((self.client.driver, self.node_id, self.index))
59
+
60
+ def __eq__(self, other: object) -> bool:
61
+ """Return whether this instance equals another."""
62
+ if not isinstance(other, Endpoint):
63
+ return False
64
+ return (
65
+ self.client.driver == other.client.driver
66
+ and self.node_id == other.node_id
67
+ and self.index == other.index
68
+ )
69
+
52
70
  @property
53
71
  def node_id(self) -> int:
54
72
  """Return node ID property."""
@@ -13,7 +13,7 @@ class LogMessageContextDataType(TypedDict, total=False):
13
13
  """Represent a log message context data dict type."""
14
14
 
15
15
  source: Literal["config", "serial", "controller", "driver"] # required
16
- type: Literal["value", "node"]
16
+ type: Literal["controller", "value", "node"]
17
17
  nodeId: int
18
18
  header: str
19
19
  direction: Literal["inbound", "outbound", "none"]
@@ -38,7 +38,7 @@ class LogMessageContext:
38
38
  return self.data["source"]
39
39
 
40
40
  @property
41
- def type(self) -> Optional[Literal["value", "node"]]:
41
+ def type(self) -> Optional[Literal["controller", "value", "node"]]:
42
42
  """Return the object type for the log message if applicable."""
43
43
  return self.data.get("type")
44
44
 
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS node."""
2
+ import logging
2
3
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, cast
3
4
 
4
5
  from ...const import (
@@ -12,7 +13,6 @@ from ...event import Event, EventBase
12
13
  from ...exceptions import (
13
14
  FailedCommand,
14
15
  NotFoundError,
15
- NotificationHasUnsupportedCommandClass,
16
16
  UnparseableValue,
17
17
  UnwriteableValue,
18
18
  )
@@ -58,6 +58,9 @@ if TYPE_CHECKING:
58
58
  from ...client import Client
59
59
 
60
60
 
61
+ _LOGGER = logging.getLogger(__package__)
62
+
63
+
61
64
  class Node(EventBase):
62
65
  """Represent a Z-Wave JS node."""
63
66
 
@@ -789,7 +792,7 @@ class Node(EventBase):
789
792
  self, cast(PowerLevelNotificationDataType, event.data)
790
793
  )
791
794
  else:
792
- raise NotificationHasUnsupportedCommandClass(event, command_class)
795
+ _LOGGER.info("Unhandled notification command class: %s", command_class.name)
793
796
 
794
797
  def handle_firmware_update_progress(self, event: Event) -> None:
795
798
  """Process a node firmware update progress event."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zwave-js-server-python
3
- Version: 0.35.2
3
+ Version: 0.35.3
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
@@ -3,7 +3,7 @@ zwave_js_server/__main__.py,sha256=1gWC927sa3FwcA47ndmrRWW0HlfYVdiUarjEsccRF2k,3
3
3
  zwave_js_server/client.py,sha256=5t1c0xI9dokP8IOR01uMAk5oxMylAp91hTlJPkMEtRE,14827
4
4
  zwave_js_server/dump.py,sha256=hTyeW8fPleyQyYyPjFeR_JxwmFRHvtpmpn1L9uNpfiw,1213
5
5
  zwave_js_server/event.py,sha256=E2bIEb635al9MsCB5rkk3ZklU4-YkmqmXtifzlbxXaQ,1958
6
- zwave_js_server/exceptions.py,sha256=MaCynJuy2JkXA7FW_tpdpIokiHJuFoLwxktPSey5iBA,5402
6
+ zwave_js_server/exceptions.py,sha256=qN7DKIonwi96XLy37dV7am4XqXt0BnelOe1q5CPHEvw,4852
7
7
  zwave_js_server/firmware.py,sha256=F5selNpOWWICuLs3L8zBjddnGKrEmip7LriijjL9pDA,878
8
8
  zwave_js_server/version.py,sha256=RDFP2kSU3cCVIQbgMWggdeDnvhtVsZzzZg9pOjH7CC8,364
9
9
  zwave_js_server/const/__init__.py,sha256=lIPV1jBPfI1ARllkYI2TAsD30v6T9KBHJ8p6RBUG_a4,7688
@@ -23,25 +23,25 @@ zwave_js_server/const/command_class/sound_switch.py,sha256=06zOSkOyldZlDj06tLKQr
23
23
  zwave_js_server/const/command_class/thermostat.py,sha256=g46k1E0TITexnqCrasqGdU1DzN_1xV5IjaAhAUwXk4I,3450
24
24
  zwave_js_server/const/command_class/wake_up.py,sha256=lyaWK0zz-faQZnp3XaS3UMI9Q34TzhCN6Mx-NlN07vU,138
25
25
  zwave_js_server/model/__init__.py,sha256=XfyKH8lxZ3CB7CbRkOr5sR-eV0GrklZiBtNPmlnCJ_8,123
26
- zwave_js_server/model/association.py,sha256=FsgKAha7mw6dpk7u7zdQoNEajTyiL0S5eOYcY4M2Rx4,529
26
+ zwave_js_server/model/association.py,sha256=GIrgo-3uxQxFnCH8PJ6TtGRoBW9Ak3iKWTJbY_qg2SM,536
27
27
  zwave_js_server/model/command_class.py,sha256=pb_aXIl1_r9iHzdEyRr300y5xu62uE6GzmF6540CQd4,1256
28
28
  zwave_js_server/model/device_class.py,sha256=KpSM101bGa_3Mig4C-_rkE4CzqImK2JPIUtlG-TFcvU,1886
29
29
  zwave_js_server/model/device_config.py,sha256=7NaMa4BZ5tGe2p0YtOQFIUjBwRVF7GYWVExLwAgIUtE,6659
30
30
  zwave_js_server/model/driver.py,sha256=dwbLNWdzKQa50191zWMP9duZVag0Ns4FnGLi8lTwxCE,6022
31
- zwave_js_server/model/endpoint.py,sha256=DwthJmJ9vw6jmCFowykaAtutK-hO5qBO7EkkEcKtSFg,5153
31
+ zwave_js_server/model/endpoint.py,sha256=EIRT1h8Fzf0BYFiGv224vQLRLVlUY_XgVCRwVTYrcEc,5784
32
32
  zwave_js_server/model/firmware.py,sha256=0AlV2mbjlmejV1eh0oHCUU-2Ysyec9a0X9BTvHG3wYs,2493
33
33
  zwave_js_server/model/log_config.py,sha256=F-QM7oHUXAfAxbdkrvmi6k6woM4VOwxB3qRrGmTQiQA,1722
34
- zwave_js_server/model/log_message.py,sha256=qlbDSLbs60bRwKXuQ6goDZST2q-5qVAfyvmCMBn1T9U,5831
34
+ zwave_js_server/model/log_message.py,sha256=IxZ4USpXTeHsuRNS61NDPYMSIflv1KDO_EjUy4_vavE,5859
35
35
  zwave_js_server/model/notification.py,sha256=db-u-wIfYhAHH3IATOeBwkU7wdjRM6yELY6Epkk3-tI,5286
36
36
  zwave_js_server/model/utils.py,sha256=fLs1pOKG53yWQggBWUKvPgzlT0JkK3biLzRkhPBNArI,814
37
37
  zwave_js_server/model/value.py,sha256=2ntVIoaZu3QHcO_zVzyyCtum4UWHOzPDzUyfHdSceTw,8753
38
38
  zwave_js_server/model/version.py,sha256=W1H-UbhKdgMW5KdnY9MUfRFibfMZSOD3nljXOv1ZVVM,1398
39
- zwave_js_server/model/controller/__init__.py,sha256=AOPCdje-xLh7LwCjIxzypY6AOf987khztHHfURRvfwE,27086
39
+ zwave_js_server/model/controller/__init__.py,sha256=at_A52Bn-W-QSMN7HUtZOSkeR6UVUB3MfQIFNu238rY,28782
40
40
  zwave_js_server/model/controller/data_model.py,sha256=98tvw-oRgAIO4tp6XZ0cTA-4advK-oZN-lbVsGNnhTs,975
41
41
  zwave_js_server/model/controller/event_model.py,sha256=stGDkUWDdcb0x6ltNfyJLf2fFEV7GIJQoKvODUDGP8s,4733
42
42
  zwave_js_server/model/controller/inclusion_and_provisioning.py,sha256=6sB4d-bjOyxJXMLNevuYcv3j22qdLW0Gg8UjFcBE58A,6010
43
43
  zwave_js_server/model/controller/statistics.py,sha256=to7RVuQztmmgMDSuK9LuhCKpC1ElOLSoan31EUY5_OM,2819
44
- zwave_js_server/model/node/__init__.py,sha256=jXEgyt9TtlFC7WL8I5b2QlzoydiYQmIKIgP0IgLNlbM,28869
44
+ zwave_js_server/model/node/__init__.py,sha256=zbiW9MUiq7E2pEI81WaYJPPd1oTB6k5TyHII_f7cRAY,28893
45
45
  zwave_js_server/model/node/data_model.py,sha256=Zdl68Oa9vUn2wegriFOcU70Q2yJO41rGKpdAdIbbtAU,1730
46
46
  zwave_js_server/model/node/event_model.py,sha256=kY-HxdRpJUGiQaM4T7DInQBJ4rf4pw1JY-nImsF-1kY,6055
47
47
  zwave_js_server/model/node/health_check.py,sha256=EAOMBkMKd5q--fhax2GvJhWdhuuv5dX_-2Hf_mczODs,6054
@@ -54,9 +54,9 @@ zwave_js_server/util/node.py,sha256=KUg-Z-7hdDLGKKCYLktc4oOgiPbDT7ZUYqUH_IPLwO4,
54
54
  zwave_js_server/util/command_class/__init__.py,sha256=sRxti47ekLTzfk8B609CMQumIbcD6mon2ZS0zwh9omY,59
55
55
  zwave_js_server/util/command_class/meter.py,sha256=Qkif1ul4KpV_k6Dc7yNXlSjlJLLTH8mCitgQk9J9W0A,1277
56
56
  zwave_js_server/util/command_class/multilevel_sensor.py,sha256=p92YLNRze5z3UWhfIDJO95F-j5tqx1PKUG9oamo9Dng,1446
57
- zwave_js_server_python-0.35.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
58
- zwave_js_server_python-0.35.2.dist-info/METADATA,sha256=WCP_FOEQDlPYUMFuiX0mipVgUpw0OcebMR_kTxVRkA4,1712
59
- zwave_js_server_python-0.35.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
60
- zwave_js_server_python-0.35.2.dist-info/entry_points.txt,sha256=_8Swg1yhKiBElo6k1fxIEd6E8uPz8PDxQpwQoZ29FZE,74
61
- zwave_js_server_python-0.35.2.dist-info/top_level.txt,sha256=-hwsl-i4Av5Op_yfOHC_OP56KPmzp_iVEkeohRIN5Ng,16
62
- zwave_js_server_python-0.35.2.dist-info/RECORD,,
57
+ zwave_js_server_python-0.35.3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
58
+ zwave_js_server_python-0.35.3.dist-info/METADATA,sha256=G7dbpdcV2FRHWGV50Eh9ccd_dXq4_Ir27YAuykoblVM,1712
59
+ zwave_js_server_python-0.35.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
60
+ zwave_js_server_python-0.35.3.dist-info/entry_points.txt,sha256=_8Swg1yhKiBElo6k1fxIEd6E8uPz8PDxQpwQoZ29FZE,74
61
+ zwave_js_server_python-0.35.3.dist-info/top_level.txt,sha256=-hwsl-i4Av5Op_yfOHC_OP56KPmzp_iVEkeohRIN5Ng,16
62
+ zwave_js_server_python-0.35.3.dist-info/RECORD,,