zwave-js-server-python 0.55.2__tar.gz → 0.55.4__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/PKG-INFO +1 -1
  2. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/client.py +1 -0
  3. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/__init__.py +2 -1
  4. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/barrier_operator.py +1 -0
  5. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/basic.py +1 -0
  6. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/central_scene.py +1 -0
  7. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/color_switch.py +1 -0
  8. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/energy_production.py +1 -0
  9. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/entry_control.py +1 -0
  10. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/humidity_control.py +1 -0
  11. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/lock.py +1 -0
  12. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/meter.py +1 -0
  13. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/multilevel_switch.py +1 -0
  14. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/power_level.py +1 -0
  15. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/protection.py +1 -0
  16. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/scene_activation.py +1 -0
  17. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/sound_switch.py +1 -0
  18. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/thermostat.py +1 -0
  19. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/wake_up.py +1 -0
  20. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/window_covering.py +1 -0
  21. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/dump.py +1 -0
  22. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/event.py +5 -1
  23. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/exceptions.py +1 -0
  24. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/firmware.py +1 -0
  25. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/association.py +1 -0
  26. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/command_class.py +1 -0
  27. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/controller/__init__.py +9 -6
  28. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/controller/data_model.py +1 -0
  29. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/controller/event_model.py +1 -0
  30. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/controller/firmware.py +1 -0
  31. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/controller/inclusion_and_provisioning.py +1 -0
  32. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/controller/rebuild_routes.py +1 -0
  33. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/controller/statistics.py +1 -0
  34. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/device_class.py +11 -6
  35. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/device_config.py +1 -0
  36. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/driver.py +1 -0
  37. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/duration.py +1 -0
  38. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/endpoint.py +7 -3
  39. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/log_config.py +1 -0
  40. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/log_message.py +1 -0
  41. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/node/__init__.py +56 -44
  42. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/node/data_model.py +1 -0
  43. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/node/event_model.py +1 -0
  44. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/node/firmware.py +1 -0
  45. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/node/health_check.py +1 -0
  46. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/node/statistics.py +1 -0
  47. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/notification.py +1 -0
  48. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/statistics.py +8 -5
  49. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/utils.py +1 -0
  50. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/value.py +1 -0
  51. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/version.py +1 -0
  52. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/util/command_class/energy_production.py +1 -0
  53. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/util/command_class/meter.py +1 -0
  54. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/util/command_class/multilevel_sensor.py +1 -0
  55. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/util/helpers.py +1 -0
  56. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/util/lock.py +1 -0
  57. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/util/multicast.py +1 -0
  58. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/util/node.py +1 -0
  59. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/version.py +1 -0
  60. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server_python.egg-info/PKG-INFO +1 -1
  61. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/LICENSE +0 -0
  62. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/MANIFEST.in +0 -0
  63. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/README.md +0 -0
  64. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/pyproject.toml +0 -0
  65. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/setup.cfg +0 -0
  66. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/__init__.py +0 -0
  67. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/__main__.py +1 -1
  68. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/__init__.py +0 -0
  69. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/multilevel_sensor.py +0 -0
  70. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/const/command_class/notification.py +0 -0
  71. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/model/__init__.py +0 -0
  72. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/py.typed +0 -0
  73. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/util/__init__.py +0 -0
  74. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server/util/command_class/__init__.py +0 -0
  75. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server_python.egg-info/SOURCES.txt +0 -0
  76. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server_python.egg-info/dependency_links.txt +0 -0
  77. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server_python.egg-info/entry_points.txt +0 -0
  78. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server_python.egg-info/requires.txt +0 -0
  79. {zwave-js-server-python-0.55.2 → zwave_js_server_python-0.55.4}/zwave_js_server_python.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zwave-js-server-python
3
- Version: 0.55.2
3
+ Version: 0.55.4
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
@@ -1,4 +1,5 @@
1
1
  """Client."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import asyncio
@@ -1,4 +1,5 @@
1
1
  """Constants for the Z-Wave JS python library."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass, field
@@ -7,7 +8,7 @@ import logging
7
8
  from typing import TypedDict
8
9
 
9
10
  PACKAGE_NAME = "zwave-js-server-python"
10
- __version__ = "0.55.2"
11
+ __version__ = "0.55.4"
11
12
 
12
13
  # minimal server schema version we can handle
13
14
  MIN_SERVER_SCHEMA_VERSION = 33
@@ -1,4 +1,5 @@
1
1
  """Constants for the Barrier Operator CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import IntEnum
@@ -1,4 +1,5 @@
1
1
  """Constants for the Basic CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  EVENT_PROPERTY = "event"
@@ -1,4 +1,5 @@
1
1
  """Constants for the Central Scene CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  SCENE_PROPERTY = "scene"
@@ -1,4 +1,5 @@
1
1
  """Constants for the Color Switch CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import IntEnum
@@ -1,4 +1,5 @@
1
1
  """Constants for the Energy Production CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import IntEnum
@@ -1,4 +1,5 @@
1
1
  """Constants for the Entry Control CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import IntEnum
@@ -4,6 +4,7 @@ Constants for the Humidity Control CCs.
4
4
  Includes Humidity Control Mode, Humidity Control Operating State,
5
5
  and Humidity Control Setpoint CCs.
6
6
  """
7
+
7
8
  from __future__ import annotations
8
9
 
9
10
  from enum import IntEnum
@@ -3,6 +3,7 @@ Constants for lock related CCs.
3
3
 
4
4
  Includes Door Lock and Lock CCs.
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  from dataclasses import dataclass, field
@@ -1,4 +1,5 @@
1
1
  """Constants for Meter CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import IntEnum
@@ -1,4 +1,5 @@
1
1
  """Constants for the Multilevel Switch CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import IntEnum
@@ -1,4 +1,5 @@
1
1
  """Constants for the Power Level Command Class."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import IntEnum
@@ -1,4 +1,5 @@
1
1
  """Constants for the Protection CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  LOCAL_PROPERTY = "local"
@@ -1,4 +1,5 @@
1
1
  """Constants for the Scene Activation CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  SCENE_ID_PROPERTY = "sceneId"
@@ -1,4 +1,5 @@
1
1
  """Constants for the Sound Switch CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import IntEnum
@@ -4,6 +4,7 @@ Constants for the Thermostat CCs.
4
4
  Includes Thermostat Fan Mode, Thermostat Fan State, Thermostat Mode, Thermostat
5
5
  Operating State, Thermostat Setback, and Thermostat Setpoint CCs.
6
6
  """
7
+
7
8
  from __future__ import annotations
8
9
 
9
10
  from enum import IntEnum
@@ -1,4 +1,5 @@
1
1
  """Constants for the Wake Up CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  WAKE_UP_INTERVAL_PROPERTY = "wakeUpInterval"
@@ -1,4 +1,5 @@
1
1
  """Constants for the Barrier Operator CC."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from enum import IntEnum
@@ -1,4 +1,5 @@
1
1
  """Dump helper."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import asyncio
@@ -1,4 +1,5 @@
1
1
  """Provide Event base classes for Z-Wave JS."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from collections.abc import Callable
@@ -62,7 +63,10 @@ class EventBase:
62
63
  def emit(self, event_name: str, data: dict) -> None:
63
64
  """Run all callbacks for an event."""
64
65
  for listener in self._listeners.get(event_name, []).copy():
65
- listener(data)
66
+ try:
67
+ listener(data)
68
+ except Exception: # pylint: disable=broad-exception-caught
69
+ LOGGER.exception("Error handling event: %s", event_name)
66
70
 
67
71
  def _handle_event_protocol(self, event: Event) -> None:
68
72
  """Process an event based on event protocol."""
@@ -1,4 +1,5 @@
1
1
  """Exceptions for zwave-js-server."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from typing import TYPE_CHECKING
@@ -1,4 +1,5 @@
1
1
  """Firmware update helper."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import asyncio
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the association."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass, field
@@ -3,6 +3,7 @@ Model for Zwave Command Class Info.
3
3
 
4
4
  https://zwave-js.github.io/node-zwave-js/#/api/endpoint?id=commandclasses
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  from typing import TypedDict
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS controller."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass
@@ -350,9 +351,11 @@ class Controller(EventBase):
350
351
  await self.client.async_send_command(
351
352
  {
352
353
  "command": "controller.provision_smart_start_node",
353
- "entry": provisioning_info
354
- if isinstance(provisioning_info, str)
355
- else provisioning_info.to_dict(),
354
+ "entry": (
355
+ provisioning_info
356
+ if isinstance(provisioning_info, str)
357
+ else provisioning_info.to_dict()
358
+ ),
356
359
  },
357
360
  require_schema=11,
358
361
  )
@@ -870,9 +873,9 @@ class Controller(EventBase):
870
873
 
871
874
  def handle_firmware_update_progress(self, event: Event) -> None:
872
875
  """Process a firmware update progress event."""
873
- self._firmware_update_progress = event.data[
874
- "firmware_update_progress"
875
- ] = ControllerFirmwareUpdateProgress(event.data["progress"])
876
+ self._firmware_update_progress = event.data["firmware_update_progress"] = (
877
+ ControllerFirmwareUpdateProgress(event.data["progress"])
878
+ )
876
879
 
877
880
  def handle_firmware_update_finished(self, event: Event) -> None:
878
881
  """Process a firmware update finished event."""
@@ -1,4 +1,5 @@
1
1
  """Data model for a Z-Wave JS controller."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from typing import TypedDict
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS controller's events."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from typing import Literal, TypedDict
@@ -1,4 +1,5 @@
1
1
  """Provide a model for Z-Wave controller firmware."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass, field
@@ -1,4 +1,5 @@
1
1
  """Provide a model for inclusion and provisioning."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass
@@ -1,4 +1,5 @@
1
1
  """Provide models for rebuilding routes."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS controller's statistics."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from contextlib import suppress
@@ -3,6 +3,7 @@ Model for a Zwave Node's device class.
3
3
 
4
4
  https://zwave-js.github.io/node-zwave-js/#/api/node?id=deviceclass
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  from dataclasses import dataclass
@@ -39,29 +40,33 @@ class DeviceClass:
39
40
 
40
41
  def __init__(self, data: DeviceClassDataType) -> None:
41
42
  """Initialize."""
42
- self.data = data
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"]
43
48
 
44
49
  @property
45
50
  def basic(self) -> DeviceClassItem:
46
51
  """Return basic DeviceClass."""
47
- return DeviceClassItem(**self.data["basic"])
52
+ return self._basic
48
53
 
49
54
  @property
50
55
  def generic(self) -> DeviceClassItem:
51
56
  """Return generic DeviceClass."""
52
- return DeviceClassItem(**self.data["generic"])
57
+ return self._generic
53
58
 
54
59
  @property
55
60
  def specific(self) -> DeviceClassItem:
56
61
  """Return specific DeviceClass."""
57
- return DeviceClassItem(**self.data["specific"])
62
+ return self._specific
58
63
 
59
64
  @property
60
65
  def mandatory_supported_ccs(self) -> list[int]:
61
66
  """Return list of mandatory Supported CC id's."""
62
- return self.data["mandatorySupportedCCs"]
67
+ return self._mandatory_supported_ccs
63
68
 
64
69
  @property
65
70
  def mandatory_controlled_ccs(self) -> list[int]:
66
71
  """Return list of mandatory Controlled CC id's."""
67
- return self.data["mandatoryControlledCCs"]
72
+ return self._mandatory_controlled_ccs
@@ -3,6 +3,7 @@ Model for a Zwave Node's device config.
3
3
 
4
4
  https://zwave-js.github.io/node-zwave-js/#/api/node?id=deviceconfig
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  from typing import Any, Literal, TypedDict
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS Driver."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from typing import TYPE_CHECKING, Any, Literal, cast
@@ -1,4 +1,5 @@
1
1
  """Provide a model for Z-Wave JS Duration."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass, field
@@ -3,6 +3,7 @@ Model for a Zwave Node's endpoints.
3
3
 
4
4
  https://zwave-js.github.io/node-zwave-js/#/api/endpoint?id=endpoint-properties
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  import asyncio
@@ -56,6 +57,7 @@ class Endpoint(EventBase):
56
57
  self.node = node
57
58
  self.data: EndpointDataType = data
58
59
  self.values: dict[str, ConfigurationValue | Value] = {}
60
+ self._device_class: DeviceClass | None = None
59
61
  self.update(data, values)
60
62
 
61
63
  def __repr__(self) -> str:
@@ -89,9 +91,7 @@ class Endpoint(EventBase):
89
91
  @property
90
92
  def device_class(self) -> DeviceClass | None:
91
93
  """Return the device_class."""
92
- if (device_class := self.data.get("deviceClass")) is None:
93
- return None
94
- return DeviceClass(device_class)
94
+ return self._device_class
95
95
 
96
96
  @property
97
97
  def installer_icon(self) -> int | None:
@@ -118,6 +118,10 @@ class Endpoint(EventBase):
118
118
  ) -> None:
119
119
  """Update the endpoint data."""
120
120
  self.data = data
121
+ if (device_class := self.data.get("deviceClass")) is None:
122
+ self._device_class = None
123
+ else:
124
+ self._device_class = DeviceClass(device_class)
121
125
 
122
126
  # Remove stale values
123
127
  self.values = {
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the log config."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass
@@ -1,4 +1,5 @@
1
1
  """Provide a model for a log message event."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass, field
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS node."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import asyncio
@@ -26,7 +27,7 @@ from ...exceptions import (
26
27
  from ..command_class import CommandClassInfo
27
28
  from ..device_class import DeviceClass
28
29
  from ..device_config import DeviceConfig
29
- from ..endpoint import Endpoint
30
+ from ..endpoint import Endpoint, EndpointDataType
30
31
  from ..notification import (
31
32
  EntryControlNotification,
32
33
  EntryControlNotificationDataType,
@@ -114,6 +115,8 @@ class Node(EventBase):
114
115
  client, data.get("statistics", DEFAULT_NODE_STATISTICS)
115
116
  )
116
117
  self._firmware_update_progress: NodeFirmwareUpdateProgress | None = None
118
+ self._device_class: DeviceClass | None = None
119
+ self._last_seen: datetime | None = None
117
120
  self.values: dict[str, ConfigurationValue | Value] = {}
118
121
  self.endpoints: dict[int, Endpoint] = {}
119
122
  self.status_event = asyncio.Event()
@@ -148,9 +151,7 @@ class Node(EventBase):
148
151
  @property
149
152
  def device_class(self) -> DeviceClass | None:
150
153
  """Return the device_class."""
151
- if (device_class := self.data.get("deviceClass")) is None:
152
- return None
153
- return DeviceClass(device_class)
154
+ return self._device_class
154
155
 
155
156
  @property
156
157
  def installer_icon(self) -> int | None:
@@ -358,9 +359,7 @@ class Node(EventBase):
358
359
  @property
359
360
  def last_seen(self) -> datetime | None:
360
361
  """Return when the node was last seen."""
361
- if last_seen := self.data.get("lastSeen"):
362
- return datetime.fromisoformat(last_seen)
363
- return None
362
+ return self._last_seen
364
363
 
365
364
  @property
366
365
  def default_volume(self) -> int | float | None:
@@ -372,17 +371,35 @@ class Node(EventBase):
372
371
  """Return the default transition duration."""
373
372
  return self.data.get("defaultTransitionDuration")
374
373
 
375
- def update(self, data: NodeDataType) -> None:
376
- """Update the internal state data."""
377
- self.data = copy.deepcopy(data)
378
- self._device_config = DeviceConfig(self.data.get("deviceConfig", {}))
379
- self._statistics = NodeStatistics(
380
- self.client, self.data.get("statistics", DEFAULT_NODE_STATISTICS)
381
- )
374
+ def _update_endpoints(self, endpoints: list[EndpointDataType]) -> None:
375
+ """Update the endpoints data."""
376
+ new_endpoints_data = {endpoint["index"]: endpoint for endpoint in endpoints}
377
+ new_endpoint_idxs = set(new_endpoints_data)
378
+ stale_endpoint_idxs = set(self.endpoints) - new_endpoint_idxs
379
+
380
+ # Remove stale endpoints
381
+ for endpoint_idx in stale_endpoint_idxs:
382
+ self.endpoints.pop(endpoint_idx)
383
+
384
+ # Add new endpoints or update existing ones
385
+ for endpoint_idx in new_endpoint_idxs:
386
+ endpoint = new_endpoints_data[endpoint_idx]
387
+ values = {
388
+ value_id: value
389
+ for value_id, value in self.values.items()
390
+ if self.index == value.endpoint
391
+ }
392
+ if endpoint_idx in self.endpoints:
393
+ self.endpoints[endpoint_idx].update(endpoint, values)
394
+ else:
395
+ self.endpoints[endpoint_idx] = Endpoint(
396
+ self.client, self, endpoint, values
397
+ )
382
398
 
399
+ def _update_values(self, values: list[ValueDataType]) -> None:
400
+ """Update the values data."""
383
401
  new_values_data = {
384
- _get_value_id_str_from_dict(self, val): val
385
- for val in self.data.pop("values")
402
+ _get_value_id_str_from_dict(self, val): val for val in values
386
403
  }
387
404
  new_value_ids = set(new_values_data)
388
405
  stale_value_ids = set(self.values) - new_value_ids
@@ -409,30 +426,25 @@ class Node(EventBase):
409
426
  # If we can't parse the value, don't store it
410
427
  pass
411
428
 
412
- new_endpoints_data = {
413
- endpoint["index"]: endpoint for endpoint in self.data.pop("endpoints")
414
- }
415
- new_endpoint_idxs = set(new_endpoints_data)
416
- stale_endpoint_idxs = set(self.endpoints) - new_endpoint_idxs
429
+ def update(self, data: NodeDataType) -> None:
430
+ """Update the internal state data."""
431
+ self.data = copy.deepcopy(data)
432
+ self._device_config = DeviceConfig(self.data.get("deviceConfig", {}))
433
+ if (device_class := self.data.get("deviceClass")) is None:
434
+ self._device_class = None
435
+ else:
436
+ self._device_class = DeviceClass(device_class)
417
437
 
418
- # Remove stale endpoints
419
- for endpoint_idx in stale_endpoint_idxs:
420
- self.endpoints.pop(endpoint_idx)
438
+ self._statistics = NodeStatistics(
439
+ self.client, self.data.get("statistics", DEFAULT_NODE_STATISTICS)
440
+ )
441
+ if last_seen := data.get("lastSeen"):
442
+ self._last_seen = datetime.fromisoformat(last_seen)
443
+ if not self._statistics.last_seen:
444
+ self._statistics.last_seen = self.last_seen
421
445
 
422
- # Add new endpoints or update existing ones
423
- for endpoint_idx in new_endpoint_idxs - stale_endpoint_idxs:
424
- endpoint = new_endpoints_data[endpoint_idx]
425
- values = {
426
- value_id: value
427
- for value_id, value in self.values.items()
428
- if self.index == value.endpoint
429
- }
430
- if endpoint_idx in self.endpoints:
431
- self.endpoints[endpoint_idx].update(endpoint, values)
432
- else:
433
- self.endpoints[endpoint_idx] = Endpoint(
434
- self.client, self, endpoint, values
435
- )
446
+ self._update_values(self.data.pop("values"))
447
+ self._update_endpoints(self.data.pop("endpoints"))
436
448
 
437
449
  def get_command_class_values(
438
450
  self, command_class: CommandClass, endpoint: int | None = None
@@ -1099,10 +1111,10 @@ class Node(EventBase):
1099
1111
 
1100
1112
  def handle_firmware_update_progress(self, event: Event) -> None:
1101
1113
  """Process a node firmware update progress event."""
1102
- self._firmware_update_progress = event.data[
1103
- "firmware_update_progress"
1104
- ] = NodeFirmwareUpdateProgress(
1105
- self, cast(NodeFirmwareUpdateProgressDataType, event.data["progress"])
1114
+ self._firmware_update_progress = event.data["firmware_update_progress"] = (
1115
+ NodeFirmwareUpdateProgress(
1116
+ self, cast(NodeFirmwareUpdateProgressDataType, event.data["progress"])
1117
+ )
1106
1118
  )
1107
1119
 
1108
1120
  def handle_firmware_update_finished(self, event: Event) -> None:
@@ -1118,5 +1130,5 @@ class Node(EventBase):
1118
1130
  event.data["statistics_updated"] = self._statistics = NodeStatistics(
1119
1131
  self.client, statistics
1120
1132
  )
1121
- if last_seen := statistics.get("lastSeen"):
1122
- self.data["lastSeen"] = last_seen
1133
+ if self._statistics.last_seen:
1134
+ self._last_seen = self._statistics.last_seen
@@ -1,4 +1,5 @@
1
1
  """Data model for a Z-Wave JS node."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from typing import TypedDict
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS node's events."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from typing import Literal
@@ -1,4 +1,5 @@
1
1
  """Provide a model for Z-Wave firmware."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import asdict, dataclass, field
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS node's health checks and power tests."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass, field
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS node's statistics."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from contextlib import suppress
@@ -3,6 +3,7 @@ Model for a Zwave Node's Notification Event.
3
3
 
4
4
  https://zwave-js.github.io/node-zwave-js/#/api/node?id=quotnotificationquot
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  from dataclasses import dataclass, field
@@ -1,4 +1,5 @@
1
1
  """Common models for statistics."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass, field
@@ -94,9 +95,11 @@ class RouteStatistics:
94
95
  "rssi": self.data.get("rssi"),
95
96
  "repeater_rssi": self.data.get("repeaterRSSI", []),
96
97
  "route_failed_between": (
97
- self.route_failed_between[0],
98
- self.route_failed_between[1],
99
- )
100
- if self.route_failed_between
101
- else None,
98
+ (
99
+ self.route_failed_between[0],
100
+ self.route_failed_between[1],
101
+ )
102
+ if self.route_failed_between
103
+ else None
104
+ ),
102
105
  }
@@ -1,4 +1,5 @@
1
1
  """Model for utils commands."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from ..client import Client
@@ -1,4 +1,5 @@
1
1
  """Provide a model for the Z-Wave JS value."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass, field
@@ -1,4 +1,5 @@
1
1
  """Represents the version from the server."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from dataclasses import dataclass
@@ -1,4 +1,5 @@
1
1
  """Energy Production Command Class specific utility functions for values."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from ...const import CommandClass
@@ -1,4 +1,5 @@
1
1
  """Meter Command Class specific utility functions for values."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from ...const import CommandClass
@@ -1,4 +1,5 @@
1
1
  """Multilevel Sensor Command Class specific utility functions for values."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from ...const import CommandClass
@@ -1,4 +1,5 @@
1
1
  """Generic Utility helper functions."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import base64
@@ -1,4 +1,5 @@
1
1
  """Utility functions for Z-Wave JS locks."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from typing import TypedDict, cast
@@ -1,4 +1,5 @@
1
1
  """Support for multicast commands."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from typing import Any, cast
@@ -1,4 +1,5 @@
1
1
  """Utility functions for Z-Wave JS nodes."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import logging
@@ -1,4 +1,5 @@
1
1
  """Version helper."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import aiohttp
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zwave-js-server-python
3
- Version: 0.55.2
3
+ Version: 0.55.4
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
@@ -1,4 +1,5 @@
1
1
  """Basic CLI to test Z-Wave JS server."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import argparse
@@ -17,7 +18,6 @@ LOGGER = logging.getLogger(__package__)
17
18
 
18
19
  def get_arguments() -> argparse.Namespace:
19
20
  """Get parsed passed in arguments."""
20
-
21
21
  parser = argparse.ArgumentParser(description="Z-Wave JS Server Python")
22
22
  parser.add_argument("--debug", action="store_true", help="Log with debug level")
23
23
  parser.add_argument(